diff --git a/src/app/fdctl/topology.c b/src/app/fdctl/topology.c index c09006ff22..477b9b93d4 100644 --- a/src/app/fdctl/topology.c +++ b/src/app/fdctl/topology.c @@ -34,6 +34,7 @@ fd_topo_initialize( config_t * config ) { fd_topob_wksp( topo, "dedup_resolv" ); fd_topob_wksp( topo, "resolv_pack" ); fd_topob_wksp( topo, "pack_bank" ); + fd_topob_wksp( topo, "pack_poh" ); fd_topob_wksp( topo, "bank_pack" ); fd_topob_wksp( topo, "bank_poh" ); fd_topob_wksp( topo, "bank_busy" ); @@ -75,6 +76,7 @@ fd_topo_initialize( config_t * config ) { /* pack_bank is shared across all banks, so if one bank stalls due to complex transactions, the buffer neeeds to be large so that other banks can keep proceeding. */ /**/ fd_topob_link( topo, "pack_bank", "pack_bank", 65536UL, USHORT_MAX, 1UL ); + /**/ fd_topob_link( topo, "pack_poh", "pack_poh", 128UL, sizeof(fd_done_packing_t), 1UL ); FOR(bank_tile_cnt) fd_topob_link( topo, "bank_poh", "bank_poh", 16384UL, USHORT_MAX, 1UL ); FOR(bank_tile_cnt) fd_topob_link( topo, "bank_pack", "bank_pack", 16384UL, USHORT_MAX, 3UL ); /**/ fd_topob_link( topo, "poh_pack", "bank_poh", 128UL, sizeof(fd_became_leader_t), 1UL ); @@ -170,6 +172,7 @@ fd_topo_initialize( config_t * config ) { /**/ fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "poh_pack", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /**/ fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "executed_txn", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); fd_topob_tile_out( topo, "pack", 0UL, "pack_bank", 0UL ); + fd_topob_tile_out( topo, "pack", 0UL, "pack_poh", 0UL ); FOR(bank_tile_cnt) fd_topob_tile_in( topo, "bank", i, "metric_in", "pack_bank", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); FOR(bank_tile_cnt) fd_topob_tile_out( topo, "bank", i, "bank_poh", i ); FOR(bank_tile_cnt) fd_topob_tile_out( topo, "bank", i, "bank_pack", i ); @@ -177,7 +180,7 @@ fd_topo_initialize( config_t * config ) { if( FD_LIKELY( config->tiles.pack.use_consumed_cus ) ) FOR(bank_tile_cnt) fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "bank_pack", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /**/ fd_topob_tile_in( topo, "poh", 0UL, "metric_in", "stake_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); - /**/ fd_topob_tile_in( topo, "poh", 0UL, "metric_in", "pack_bank", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); + /**/ fd_topob_tile_in( topo, "poh", 0UL, "metric_in", "pack_poh", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED ); /**/ fd_topob_tile_out( topo, "poh", 0UL, "poh_shred", 0UL ); /**/ fd_topob_tile_out( topo, "poh", 0UL, "poh_pack", 0UL ); FOR(shred_tile_cnt) for( ulong j=0UL; j> 32); } -FD_FN_CONST static inline ulong fd_disco_bank_sig_microblock_idx( ulong sig ) { return sig & 0xFFFFFFFFUL; } +FD_FN_CONST static inline ulong fd_disco_bank_sig_pack_idx( ulong sig ) { return sig & 0xFFFFFFFFUL; } /* TODO remove with store_int */ diff --git a/src/disco/gui/fd_gui_tile.c b/src/disco/gui/fd_gui_tile.c index 7893c9c97b..776275f603 100644 --- a/src/disco/gui/fd_gui_tile.c +++ b/src/disco/gui/fd_gui_tile.c @@ -43,7 +43,8 @@ extern uint const fdctl_commit_ref; #define IN_KIND_PLUGIN (0UL) #define IN_KIND_POH_PACK (1UL) #define IN_KIND_PACK_BANK (2UL) -#define IN_KIND_BANK_POH (3UL) +#define IN_KIND_PACK_POH (3UL) +#define IN_KIND_BANK_POH (4UL) FD_IMPORT_BINARY( firedancer_svg, "book/public/fire.svg" ); @@ -219,6 +220,8 @@ after_frag( fd_gui_ctx_t * ctx, FD_TEST( fd_disco_poh_sig_pkt_type( sig )==POH_PKT_TYPE_BECAME_LEADER ); fd_became_leader_t * became_leader = (fd_became_leader_t *)ctx->buf; fd_gui_became_leader( ctx->gui, fd_frag_meta_ts_decomp( tspub, fd_tickcount() ), fd_disco_poh_sig_slot( sig ), became_leader->slot_start_ns, became_leader->slot_end_ns, became_leader->limits.slot_max_cost, became_leader->max_microblocks_in_slot ); + } else if( FD_UNLIKELY( ctx->in_kind[ in_idx ]==IN_KIND_PACK_POH ) ) { + fd_gui_unbecame_leader( ctx->gui, fd_frag_meta_ts_decomp( tspub, fd_tickcount() ), fd_disco_poh_sig_slot( sig ), ((fd_done_packing_t *)ctx->buf)->microblocks_in_slot ); } else if( FD_UNLIKELY( ctx->in_kind[ in_idx ]==IN_KIND_PACK_BANK ) ) { if( FD_LIKELY( fd_disco_poh_sig_pkt_type( sig )==POH_PKT_TYPE_MICROBLOCK ) ) { FD_TEST( szmicroblock_idx, trailer->pack_txn_idx ); - } else if( FD_LIKELY( fd_disco_poh_sig_pkt_type( sig )==POH_PKT_TYPE_DONE_PACKING ) ) { - fd_gui_unbecame_leader( ctx->gui, fd_frag_meta_ts_decomp( tspub, fd_tickcount() ), fd_disco_poh_sig_slot( sig ), ((fd_done_packing_t *)ctx->buf)->microblocks_in_slot ); } else { FD_LOG_ERR(( "unexpected poh packet type %lu", fd_disco_poh_sig_pkt_type( sig ) )); } @@ -511,6 +512,7 @@ unprivileged_init( fd_topo_t * topo, if( FD_LIKELY( !strcmp( link->name, "plugin_out" ) ) ) ctx->in_kind[ i ] = IN_KIND_PLUGIN; else if( FD_LIKELY( !strcmp( link->name, "poh_pack" ) ) ) ctx->in_kind[ i ] = IN_KIND_POH_PACK; else if( FD_LIKELY( !strcmp( link->name, "pack_bank" ) ) ) ctx->in_kind[ i ] = IN_KIND_PACK_BANK; + else if( FD_LIKELY( !strcmp( link->name, "pack_poh" ) ) ) ctx->in_kind[ i ] = IN_KIND_PACK_POH; else if( FD_LIKELY( !strcmp( link->name, "bank_poh" ) ) ) ctx->in_kind[ i ] = IN_KIND_BANK_POH; else FD_LOG_ERR(( "gui tile has unexpected input link %lu %s", i, link->name )); diff --git a/src/disco/pack/fd_pack_tile.c b/src/disco/pack/fd_pack_tile.c index 1877f77d30..9bad1f1a2d 100644 --- a/src/disco/pack/fd_pack_tile.c +++ b/src/disco/pack/fd_pack_tile.c @@ -137,12 +137,16 @@ typedef struct { ulong leader_slot; void const * leader_bank; + fd_became_leader_t _became_leader[1]; + /* The number of microblocks we have packed for the current leader slot. Will always be <= slot_max_microblocks. We must track this so that when we are done we can tell the PoH tile how many microblocks to expect in the slot. */ ulong slot_microblock_cnt; + uint pack_idx; + ulong pack_txn_cnt; /* total num transactions packed since startup */ /* The maximum number of microblocks that can be packed in this slot. @@ -238,10 +242,15 @@ typedef struct { least bank_ready_at[x]. */ long bank_ready_at[ FD_PACK_MAX_BANK_TILES ]; - fd_wksp_t * out_mem; - ulong out_chunk0; - ulong out_wmark; - ulong out_chunk; + fd_wksp_t * bank_out_mem; + ulong bank_out_chunk0; + ulong bank_out_wmark; + ulong bank_out_chunk; + + fd_wksp_t * poh_out_mem; + ulong poh_out_chunk0; + ulong poh_out_wmark; + ulong poh_out_chunk; ulong insert_result[ FD_PACK_INSERT_RETVAL_CNT ]; fd_histf_t schedule_duration[ 1 ]; @@ -527,18 +536,12 @@ after_credit( fd_pack_ctx_t * ctx, if( FD_UNLIKELY( ctx->approx_wallclock_ns>=ctx->slot_end_ns && ctx->leader_slot!=ULONG_MAX ) ) { *charge_busy = 1; - if( FD_UNLIKELY( ctx->slot_microblock_cntslot_max_microblocks )) { - /* As an optimization, The PoH tile will automatically end a slot - if it receives the maximum allowed microblocks, since it knows - there is nothing left to receive. In that case, we don't need - to send a DONE_PACKING notification, since they are already on - the next slot. If we did send one it would just get dropped. */ - fd_done_packing_t * done_packing = fd_chunk_to_laddr( ctx->out_mem, ctx->out_chunk ); - done_packing->microblocks_in_slot = ctx->slot_microblock_cnt; + fd_done_packing_t * done_packing = fd_chunk_to_laddr( ctx->poh_out_mem, ctx->poh_out_chunk ); + done_packing->microblocks_in_slot = ctx->slot_microblock_cnt; - fd_stem_publish( stem, 0UL, fd_disco_poh_sig( ctx->leader_slot, POH_PKT_TYPE_DONE_PACKING, ULONG_MAX ), ctx->out_chunk, sizeof(fd_done_packing_t), 0UL, 0UL, fd_frag_meta_ts_comp( fd_tickcount() ) ); - ctx->out_chunk = fd_dcache_compact_next( ctx->out_chunk, sizeof(fd_done_packing_t), ctx->out_chunk0, ctx->out_wmark ); - } + fd_stem_publish( stem, 1UL, fd_disco_bank_sig( ctx->leader_slot, ctx->pack_idx ), ctx->poh_out_chunk, sizeof(fd_done_packing_t), 0UL, 0UL, fd_frag_meta_ts_comp( fd_tickcount() ) ); + ctx->poh_out_chunk = fd_dcache_compact_next( ctx->poh_out_chunk, sizeof(fd_done_packing_t), ctx->poh_out_chunk0, ctx->poh_out_wmark ); + ctx->pack_idx++; log_end_block_metrics( ctx, now, "time" ); ctx->drain_banks = 1; @@ -682,7 +685,7 @@ after_credit( fd_pack_ctx_t * ctx, break; } - fd_txn_p_t * microblock_dst = fd_chunk_to_laddr( ctx->out_mem, ctx->out_chunk ); + fd_txn_p_t * microblock_dst = fd_chunk_to_laddr( ctx->bank_out_mem, ctx->bank_out_chunk ); long schedule_duration = -fd_tickcount(); ulong schedule_cnt = fd_pack_schedule_next_microblock( ctx->pack, CUS_PER_MICROBLOCK, VOTE_FRACTION, (ulong)i, flags, microblock_dst ); schedule_duration += fd_tickcount(); @@ -693,11 +696,12 @@ after_credit( fd_pack_ctx_t * ctx, long now2 = fd_tickcount(); ulong tsorig = (ulong)fd_frag_meta_ts_comp( now ); /* A bound on when we observed bank was idle */ ulong tspub = (ulong)fd_frag_meta_ts_comp( now2 ); - ulong chunk = ctx->out_chunk; + ulong chunk = ctx->bank_out_chunk; ulong msg_sz = schedule_cnt*sizeof(fd_txn_p_t); fd_microblock_bank_trailer_t * trailer = (fd_microblock_bank_trailer_t*)(microblock_dst+schedule_cnt); trailer->bank = ctx->leader_bank; trailer->microblock_idx = ctx->slot_microblock_cnt; + trailer->pack_idx = ctx->pack_idx; trailer->pack_txn_idx = ctx->pack_txn_cnt; trailer->is_bundle = !!(microblock_dst->flags & FD_TXN_P_FLAGS_BUNDLE); @@ -705,8 +709,9 @@ after_credit( fd_pack_ctx_t * ctx, fd_stem_publish( stem, 0UL, sig, chunk, msg_sz+sizeof(fd_microblock_bank_trailer_t), 0UL, tsorig, tspub ); ctx->bank_expect[ i ] = stem->seqs[0]-1UL; ctx->bank_ready_at[i] = now2 + (long)ctx->microblock_duration_ticks; - ctx->out_chunk = fd_dcache_compact_next( ctx->out_chunk, msg_sz+sizeof(fd_microblock_bank_trailer_t), ctx->out_chunk0, ctx->out_wmark ); + ctx->bank_out_chunk = fd_dcache_compact_next( ctx->bank_out_chunk, msg_sz+sizeof(fd_microblock_bank_trailer_t), ctx->bank_out_chunk0, ctx->bank_out_wmark ); ctx->slot_microblock_cnt += fd_ulong_if( trailer->is_bundle, schedule_cnt, 1UL ); + ctx->pack_idx += fd_uint_if( trailer->is_bundle, (uint)schedule_cnt, 1U ); ctx->pack_txn_cnt += schedule_cnt; ctx->bank_idle_bitset = fd_ulong_pop_lsb( ctx->bank_idle_bitset ); @@ -778,61 +783,7 @@ during_frag( fd_pack_ctx_t * ctx, if( FD_UNLIKELY( chunkin[ in_idx ].chunk0 || chunk>ctx->in[ in_idx ].wmark || sz!=sizeof(fd_became_leader_t) ) ) FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]", chunk, sz, ctx->in[ in_idx ].chunk0, ctx->in[ in_idx ].wmark )); - long now_ticks = fd_tickcount(); - long now_ns = fd_log_wallclock(); - - if( FD_UNLIKELY( ctx->leader_slot!=ULONG_MAX ) ) { - FD_LOG_WARNING(( "switching to slot %lu while packing for slot %lu. Draining bank tiles.", fd_disco_poh_sig_slot( sig ), ctx->leader_slot )); - log_end_block_metrics( ctx, now_ticks, "switch" ); - ctx->drain_banks = 1; - ctx->leader_slot = ULONG_MAX; - ctx->slot_microblock_cnt = 0UL; - fd_pack_end_block( ctx->pack ); - remove_ib( ctx ); - } - ctx->leader_slot = fd_disco_poh_sig_slot( sig ); - - ulong exp_cnt = fd_pack_expire_before( ctx->pack, fd_ulong_max( ctx->leader_slot, TRANSACTION_LIFETIME_SLOTS )-TRANSACTION_LIFETIME_SLOTS ); - FD_MCNT_INC( PACK, TRANSACTION_EXPIRED, exp_cnt ); - - fd_became_leader_t * became_leader = (fd_became_leader_t *)dcache_entry; - ctx->leader_bank = became_leader->bank; - ctx->slot_max_microblocks = became_leader->max_microblocks_in_slot; - /* Reserve some space in the block for ticks */ - ctx->slot_max_data = (ctx->larger_shred_limits_per_block ? LARGER_MAX_DATA_PER_BLOCK : FD_PACK_MAX_DATA_PER_BLOCK) - - 48UL*(became_leader->ticks_per_slot+became_leader->total_skipped_ticks); - - ctx->limits.slot_max_cost = became_leader->limits.slot_max_cost; - ctx->limits.slot_max_vote_cost = became_leader->limits.slot_max_vote_cost; - ctx->limits.slot_max_write_cost_per_acct = became_leader->limits.slot_max_write_cost_per_acct; - - /* ticks_per_ns is probably relatively stable over 400ms, but not - over several hours, so we need to compute the slot duration in - milliseconds first and then convert to ticks. This doesn't need - to be super accurate, but we don't want it to vary wildly. */ - long end_ticks = now_ticks + (long)((double)fd_long_max( became_leader->slot_end_ns - now_ns, 1L )*ctx->ticks_per_ns); - /* We may still get overrun, but then we'll never use this and just - reinitialize it the next time when we actually become leader. */ - fd_pack_pacing_init( ctx->pacer, now_ticks, end_ticks, (float)ctx->ticks_per_ns, ctx->limits.slot_max_cost ); - - if( FD_UNLIKELY( ctx->crank->enabled ) ) { - /* If we get overrun, we'll just never use these values, but the - old values aren't really useful either. */ - ctx->crank->epoch = became_leader->epoch; - *(ctx->crank->prev_config) = *(became_leader->bundle->config); - memcpy( ctx->crank->recent_blockhash, became_leader->bundle->last_blockhash, 32UL ); - memcpy( ctx->crank->tip_receiver_owner, became_leader->bundle->tip_receiver_owner, 32UL ); - } - - FD_LOG_INFO(( "pack_became_leader(slot=%lu,ends_at=%ld)", ctx->leader_slot, became_leader->slot_end_ns )); - - /* The dcache might get overrun, so set slot_end_ns to 0, so if it does - the slot will get skipped. Then update it in the `after_frag` case - below to the correct value. */ - ctx->slot_end_ns = 0L; - ctx->_slot_end_ns = became_leader->slot_end_ns; - - update_metric_state( ctx, fd_tickcount(), FD_PACK_METRIC_STATE_LEADER, 1 ); + fd_memcpy( ctx->_became_leader, dcache_entry, sizeof(fd_became_leader_t) ); return; } case IN_KIND_BANK: { @@ -971,6 +922,68 @@ after_frag( fd_pack_ctx_t * ctx, case IN_KIND_POH: { if( fd_disco_poh_sig_pkt_type( sig )!=POH_PKT_TYPE_BECAME_LEADER ) return; + long now_ticks = fd_tickcount(); + long now_ns = fd_log_wallclock(); + + if( FD_UNLIKELY( ctx->leader_slot!=ULONG_MAX ) ) { + fd_done_packing_t * done_packing = fd_chunk_to_laddr( ctx->poh_out_mem, ctx->poh_out_chunk ); + done_packing->microblocks_in_slot = ctx->slot_microblock_cnt; + + fd_stem_publish( stem, 1UL, fd_disco_bank_sig( ctx->leader_slot, ctx->pack_idx ), ctx->poh_out_chunk, sizeof(fd_done_packing_t), 0UL, 0UL, fd_frag_meta_ts_comp( fd_tickcount() ) ); + ctx->poh_out_chunk = fd_dcache_compact_next( ctx->poh_out_chunk, sizeof(fd_done_packing_t), ctx->poh_out_chunk0, ctx->poh_out_wmark ); + ctx->pack_idx++; + + FD_LOG_WARNING(( "switching to slot %lu while packing for slot %lu. Draining bank tiles.", fd_disco_poh_sig_slot( sig ), ctx->leader_slot )); + log_end_block_metrics( ctx, now_ticks, "switch" ); + ctx->drain_banks = 1; + ctx->leader_slot = ULONG_MAX; + ctx->slot_microblock_cnt = 0UL; + fd_pack_end_block( ctx->pack ); + remove_ib( ctx ); + } + ctx->leader_slot = fd_disco_poh_sig_slot( sig ); + + ulong exp_cnt = fd_pack_expire_before( ctx->pack, fd_ulong_max( ctx->leader_slot, TRANSACTION_LIFETIME_SLOTS )-TRANSACTION_LIFETIME_SLOTS ); + FD_MCNT_INC( PACK, TRANSACTION_EXPIRED, exp_cnt ); + + ctx->leader_bank = ctx->_became_leader->bank; + ctx->slot_max_microblocks = ctx->_became_leader->max_microblocks_in_slot; + /* Reserve some space in the block for ticks */ + ctx->slot_max_data = (ctx->larger_shred_limits_per_block ? LARGER_MAX_DATA_PER_BLOCK : FD_PACK_MAX_DATA_PER_BLOCK) + - 48UL*(ctx->_became_leader->ticks_per_slot+ctx->_became_leader->total_skipped_ticks); + + ctx->limits.slot_max_cost = ctx->_became_leader->limits.slot_max_cost; + ctx->limits.slot_max_vote_cost = ctx->_became_leader->limits.slot_max_vote_cost; + ctx->limits.slot_max_write_cost_per_acct = ctx->_became_leader->limits.slot_max_write_cost_per_acct; + + /* ticks_per_ns is probably relatively stable over 400ms, but not + over several hours, so we need to compute the slot duration in + milliseconds first and then convert to ticks. This doesn't need + to be super accurate, but we don't want it to vary wildly. */ + long end_ticks = now_ticks + (long)((double)fd_long_max( ctx->_became_leader->slot_end_ns - now_ns, 1L )*ctx->ticks_per_ns); + /* We may still get overrun, but then we'll never use this and just + reinitialize it the next time when we actually become leader. */ + fd_pack_pacing_init( ctx->pacer, now_ticks, end_ticks, (float)ctx->ticks_per_ns, ctx->limits.slot_max_cost ); + + if( FD_UNLIKELY( ctx->crank->enabled ) ) { + /* If we get overrun, we'll just never use these values, but the + old values aren't really useful either. */ + ctx->crank->epoch = ctx->_became_leader->epoch; + *(ctx->crank->prev_config) = *(ctx->_became_leader->bundle->config); + memcpy( ctx->crank->recent_blockhash, ctx->_became_leader->bundle->last_blockhash, 32UL ); + memcpy( ctx->crank->tip_receiver_owner, ctx->_became_leader->bundle->tip_receiver_owner, 32UL ); + } + + FD_LOG_INFO(( "pack_became_leader(slot=%lu,ends_at=%ld)", ctx->leader_slot, ctx->_became_leader->slot_end_ns )); + + /* The dcache might get overrun, so set slot_end_ns to 0, so if it does + the slot will get skipped. Then update it in the `after_frag` case + below to the correct value. */ + ctx->slot_end_ns = 0L; + ctx->_slot_end_ns = ctx->_became_leader->slot_end_ns; + + update_metric_state( ctx, fd_tickcount(), FD_PACK_METRIC_STATE_LEADER, 1 ); + ctx->slot_end_ns = ctx->_slot_end_ns; fd_pack_limits_t limits[ 1 ]; limits->max_cost_per_block = ctx->limits.slot_max_cost; @@ -1099,6 +1112,7 @@ unprivileged_init( fd_topo_t * topo, if( FD_UNLIKELY( tile->in_cnt>32UL ) ) FD_LOG_ERR(( "Too many input links (%lu>32) to pack tile", tile->in_cnt )); + FD_TEST( tile->in_cntin_kind )/sizeof( ctx->in_kind[0] ) ); for( ulong i=0UL; iin_cnt; i++ ) { fd_topo_link_t const * link = &topo->links[ tile->in_link_id[ i ] ]; @@ -1178,6 +1192,7 @@ unprivileged_init( fd_topo_t * topo, ctx->max_pending_transactions = tile->pack.max_pending_transactions; ctx->leader_slot = ULONG_MAX; ctx->leader_bank = NULL; + ctx->pack_idx = 0UL; ctx->slot_microblock_cnt = 0UL; ctx->pack_txn_cnt = 0UL; ctx->slot_max_microblocks = 0UL; @@ -1229,10 +1244,15 @@ unprivileged_init( fd_topo_t * topo, ctx->in[ i ].wmark = fd_dcache_compact_wmark ( ctx->in[ i ].mem, link->dcache, link->mtu ); } - ctx->out_mem = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ 0 ] ].dcache_obj_id ].wksp_id ].wksp; - ctx->out_chunk0 = fd_dcache_compact_chunk0( ctx->out_mem, topo->links[ tile->out_link_id[ 0 ] ].dcache ); - ctx->out_wmark = fd_dcache_compact_wmark ( ctx->out_mem, topo->links[ tile->out_link_id[ 0 ] ].dcache, topo->links[ tile->out_link_id[ 0 ] ].mtu ); - ctx->out_chunk = ctx->out_chunk0; + ctx->bank_out_mem = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ 0 ] ].dcache_obj_id ].wksp_id ].wksp; + ctx->bank_out_chunk0 = fd_dcache_compact_chunk0( ctx->bank_out_mem, topo->links[ tile->out_link_id[ 0 ] ].dcache ); + ctx->bank_out_wmark = fd_dcache_compact_wmark ( ctx->bank_out_mem, topo->links[ tile->out_link_id[ 0 ] ].dcache, topo->links[ tile->out_link_id[ 0 ] ].mtu ); + ctx->bank_out_chunk = ctx->bank_out_chunk0; + + ctx->poh_out_mem = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ 1 ] ].dcache_obj_id ].wksp_id ].wksp; + ctx->poh_out_chunk0 = fd_dcache_compact_chunk0( ctx->poh_out_mem, topo->links[ tile->out_link_id[ 1 ] ].dcache ); + ctx->poh_out_wmark = fd_dcache_compact_wmark ( ctx->poh_out_mem, topo->links[ tile->out_link_id[ 1 ] ].dcache, topo->links[ tile->out_link_id[ 1 ] ].mtu ); + ctx->poh_out_chunk = ctx->poh_out_chunk0; /* Initialize metrics storage */ memset( ctx->insert_result, '\0', FD_PACK_INSERT_RETVAL_CNT * sizeof(ulong) ); diff --git a/src/disco/tiles.h b/src/disco/tiles.h index b7986a5ef6..1f329e9d1f 100644 --- a/src/disco/tiles.h +++ b/src/disco/tiles.h @@ -151,6 +151,7 @@ struct fd_microblock_bank_trailer { banks. This is used by PoH to ensure microblocks get committed in the same order they are executed. */ ulong microblock_idx; + uint pack_idx; /* A sequentially increasing index of the first transaction in the microblock, across all slots ever processed by pack. This is used diff --git a/src/discof/poh/fd_poh_tile.c b/src/discof/poh/fd_poh_tile.c index 35fd251644..e02e33051d 100644 --- a/src/discof/poh/fd_poh_tile.c +++ b/src/discof/poh/fd_poh_tile.c @@ -1775,7 +1775,7 @@ before_frag( fd_poh_ctx_t * ctx, (void)seq; if( FD_LIKELY( ctx->in_kind[ in_idx ]==IN_KIND_BANK ) ) { - ulong microblock_idx = fd_disco_bank_sig_microblock_idx( sig ); + ulong microblock_idx = fd_disco_bank_sig_pack_idx( sig ); FD_TEST( microblock_idx>=ctx->expect_microblock_idx ); /* Return the fragment to stem so we can process it later, if it's @@ -1796,7 +1796,7 @@ during_frag( fd_poh_ctx_t * ctx, ulong chunk, ulong sz, ulong ctl FD_PARAM_UNUSED ) { - + (void)sig; ctx->skip_frag = 0; if( FD_UNLIKELY( ctx->in_kind[ in_idx ]==IN_KIND_STAKE ) ) { @@ -1809,16 +1809,13 @@ during_frag( fd_poh_ctx_t * ctx, return; } - ulong pkt_type; ulong slot; switch( ctx->in_kind[ in_idx ] ) { case IN_KIND_BANK: { - pkt_type = POH_PKT_TYPE_MICROBLOCK; slot = fd_disco_bank_sig_slot( sig ); break; } case IN_KIND_PACK: { - pkt_type = fd_disco_poh_sig_pkt_type( sig ); slot = fd_disco_poh_sig_slot( sig ); break; } @@ -1826,40 +1823,36 @@ during_frag( fd_poh_ctx_t * ctx, FD_LOG_ERR(( "unexpected in_kind %d", ctx->in_kind[ in_idx ] )); } - int is_frag_for_prior_leader_slot = 0; - if( FD_LIKELY( pkt_type==POH_PKT_TYPE_DONE_PACKING || pkt_type==POH_PKT_TYPE_MICROBLOCK ) ) { - /* The following sequence is possible... + /* The following sequence is possible... - 1. We become leader in slot 10 - 2. While leader, we switch to a fork that is on slot 8, where - we are leader - 3. We get the in-flight microblocks for slot 10 + 1. We become leader in slot 10 + 2. While leader, we switch to a fork that is on slot 8, where we + are leader + 3. We get the in-flight microblocks for slot 10 - These in-flight microblocks need to be dropped, so we check - against the high water mark (highwater_leader_slot) rather than - the current hashcnt here when determining what to drop. + These in-flight microblocks need to be dropped, so we check against + the high water mark (highwater_leader_slot) rather than the current + hashcnt here when determining what to drop. - We know if the slot is lower than the high water mark it's from a stale - leader slot, because we will not become leader for the same slot twice - even if we are reset back in time (to prevent duplicate blocks). */ - is_frag_for_prior_leader_slot = slothighwater_leader_slot; - } + We know if the slot is lower than the high water mark it's from a + stale leader slot, because we will not become leader for the same + slot twice even if we are reset back in time (to prevent duplicate + blocks). */ + int is_frag_for_prior_leader_slot = slothighwater_leader_slot; if( FD_UNLIKELY( ctx->in_kind[ in_idx ]==IN_KIND_PACK ) ) { /* We now know the real amount of microblocks published, so set an exact bound for once we receive them. */ ctx->skip_frag = 1; - if( pkt_type==POH_PKT_TYPE_DONE_PACKING ) { - if( FD_UNLIKELY( is_frag_for_prior_leader_slot ) ) return; - - FD_TEST( ctx->microblocks_lower_bound<=ctx->max_microblocks_per_slot ); - fd_done_packing_t const * done_packing = fd_chunk_to_laddr( ctx->in[ in_idx ].mem, chunk ); - FD_LOG_INFO(( "done_packing(slot=%lu,seen_microblocks=%lu,microblocks_in_slot=%lu)", - ctx->slot, - ctx->microblocks_lower_bound, - done_packing->microblocks_in_slot )); - ctx->microblocks_lower_bound += ctx->max_microblocks_per_slot - done_packing->microblocks_in_slot; - } + if( FD_UNLIKELY( is_frag_for_prior_leader_slot ) ) return; + + FD_TEST( ctx->microblocks_lower_bound<=ctx->max_microblocks_per_slot ); + fd_done_packing_t const * done_packing = fd_chunk_to_laddr( ctx->in[ in_idx ].mem, chunk ); + FD_LOG_INFO(( "done_packing(slot=%lu,seen_microblocks=%lu,microblocks_in_slot=%lu)", + ctx->slot, + ctx->microblocks_lower_bound, + done_packing->microblocks_in_slot )); + ctx->microblocks_lower_bound += ctx->max_microblocks_per_slot - done_packing->microblocks_in_slot; return; } else { if( FD_UNLIKELY( chunkin[ in_idx ].chunk0 || chunk>ctx->in[ in_idx ].wmark || sz>USHORT_MAX ) ) diff --git a/src/discoh/bank/fd_bank_tile.c b/src/discoh/bank/fd_bank_tile.c index 451c6939eb..cef49085e1 100644 --- a/src/discoh/bank/fd_bank_tile.c +++ b/src/discoh/bank/fd_bank_tile.c @@ -23,7 +23,7 @@ typedef struct { uchar * txn_sidecar_mem; void const * _bank; - ulong _microblock_idx; + ulong _pack_idx; ulong _txn_idx; int _is_bundle; @@ -46,8 +46,6 @@ typedef struct { fd_pack_rebate_sum_t rebater[ 1 ]; struct { - ulong slot_acquire[ 3 ]; - ulong txn_load_address_lookup_tables[ 6 ]; ulong transaction_result[ 41 ]; ulong processing_failed; @@ -76,8 +74,6 @@ scratch_footprint( fd_topo_tile_t const * tile ) { static inline void metrics_write( fd_bank_ctx_t * ctx ) { - FD_MCNT_ENUM_COPY( BANK, SLOT_ACQUIRE, ctx->metrics.slot_acquire ); - FD_MCNT_ENUM_COPY( BANK, TRANSACTION_LOAD_ADDRESS_TABLES, ctx->metrics.txn_load_address_lookup_tables ); FD_MCNT_ENUM_COPY( BANK, TRANSACTION_RESULT, ctx->metrics.transaction_result ); @@ -130,7 +126,7 @@ during_frag( fd_bank_ctx_t * ctx, fd_memcpy( dst, src, sz-sizeof(fd_microblock_bank_trailer_t) ); fd_microblock_bank_trailer_t * trailer = (fd_microblock_bank_trailer_t *)( src+sz-sizeof(fd_microblock_bank_trailer_t) ); ctx->_bank = trailer->bank; - ctx->_microblock_idx = trailer->microblock_idx; + ctx->_pack_idx = trailer->pack_idx; ctx->_txn_idx = trailer->pack_txn_idx; ctx->_is_bundle = trailer->is_bundle; } @@ -336,7 +332,7 @@ handle_microblock( fd_bank_ctx_t * ctx, PoH should eventually flush the pipeline before ending the slot. */ metrics_write( ctx ); - ulong bank_sig = fd_disco_bank_sig( slot, ctx->_microblock_idx ); + ulong bank_sig = fd_disco_bank_sig( slot, ctx->_pack_idx ); /* We always need to publish, even if there are no successfully executed transactions so the PoH tile can keep an accurate count of microblocks @@ -489,7 +485,7 @@ handle_bundle( fd_bank_ctx_t * ctx, trailer->pack_txn_idx = ctx->_txn_idx + i; trailer->tips = tips[ i ]; - ulong bank_sig = fd_disco_bank_sig( slot, ctx->_microblock_idx+i ); + ulong bank_sig = fd_disco_bank_sig( slot, ctx->_pack_idx+i ); long tickcount = fd_tickcount(); long microblock_start_ticks = fd_frag_meta_ts_decomp( begin_tspub, tickcount ); diff --git a/src/discoh/poh/fd_poh_tile.c b/src/discoh/poh/fd_poh_tile.c index 57f8dea4ce..7623bd14ff 100644 --- a/src/discoh/poh/fd_poh_tile.c +++ b/src/discoh/poh/fd_poh_tile.c @@ -441,7 +441,7 @@ typedef struct { little bit over-strict, we just need to ensure that microblocks with conflicting accounts execute in order, but this is easiest to implement for now. */ - ulong expect_microblock_idx; + uint expect_pack_idx; /* The PoH tile must never drop microblocks that get committed by the bank, so it needs to always be able to mixin a microblock hash. @@ -1095,7 +1095,6 @@ fd_ext_poh_begin_leader( void const * bank, ctx->current_leader_bank = bank; ctx->microblocks_lower_bound = 0UL; ctx->cus_used = 0UL; - ctx->expect_microblock_idx = 0UL; ctx->limits.slot_max_cost = cus_block_limit; ctx->limits.slot_max_vote_cost = cus_vote_cost_limit; @@ -1775,16 +1774,12 @@ before_frag( fd_poh_ctx_t * ctx, ulong sig ) { (void)seq; - if( FD_LIKELY( ctx->in_kind[ in_idx ]==IN_KIND_BANK ) ) { - ulong microblock_idx = fd_disco_bank_sig_microblock_idx( sig ); - FD_TEST( microblock_idx>=ctx->expect_microblock_idx ); + if( FD_LIKELY( ctx->in_kind[ in_idx ]!=IN_KIND_BANK && ctx->in_kind[ in_idx ]!=IN_KIND_PACK ) ) return 0; - /* Return the fragment to stem so we can process it later, if it's - not next in the sequence. */ - if( FD_UNLIKELY( microblock_idx>ctx->expect_microblock_idx ) ) return -1; - - ctx->expect_microblock_idx++; - } + uint pack_idx = (uint)fd_disco_bank_sig_pack_idx( sig ); + FD_TEST( ((int)(pack_idx-ctx->expect_pack_idx))>=0L ); + if( FD_UNLIKELY( pack_idx!=ctx->expect_pack_idx ) ) return -1; + ctx->expect_pack_idx++; return 0; } @@ -1797,7 +1792,6 @@ during_frag( fd_poh_ctx_t * ctx, ulong chunk, ulong sz, ulong ctl FD_PARAM_UNUSED ) { - ctx->skip_frag = 0; if( FD_UNLIKELY( ctx->in_kind[ in_idx ]==IN_KIND_STAKE ) ) { @@ -1810,16 +1804,13 @@ during_frag( fd_poh_ctx_t * ctx, return; } - ulong pkt_type; ulong slot; switch( ctx->in_kind[ in_idx ] ) { case IN_KIND_BANK: { - pkt_type = POH_PKT_TYPE_MICROBLOCK; slot = fd_disco_bank_sig_slot( sig ); break; } case IN_KIND_PACK: { - pkt_type = fd_disco_poh_sig_pkt_type( sig ); slot = fd_disco_poh_sig_slot( sig ); break; } @@ -1827,40 +1818,35 @@ during_frag( fd_poh_ctx_t * ctx, FD_LOG_ERR(( "unexpected in_kind %d", ctx->in_kind[ in_idx ] )); } - int is_frag_for_prior_leader_slot = 0; - if( FD_LIKELY( pkt_type==POH_PKT_TYPE_DONE_PACKING || pkt_type==POH_PKT_TYPE_MICROBLOCK ) ) { - /* The following sequence is possible... + /* The following sequence is possible... - 1. We become leader in slot 10 - 2. While leader, we switch to a fork that is on slot 8, where - we are leader - 3. We get the in-flight microblocks for slot 10 + 1. We become leader in slot 10 + 2. While leader, we switch to a fork that is on slot 8, where + we are leader + 3. We get the in-flight microblocks for slot 10 - These in-flight microblocks need to be dropped, so we check - against the high water mark (highwater_leader_slot) rather than - the current hashcnt here when determining what to drop. + These in-flight microblocks need to be dropped, so we check + against the high water mark (highwater_leader_slot) rather than + the current hashcnt here when determining what to drop. - We know if the slot is lower than the high water mark it's from a stale - leader slot, because we will not become leader for the same slot twice - even if we are reset back in time (to prevent duplicate blocks). */ - is_frag_for_prior_leader_slot = slothighwater_leader_slot; - } + We know if the slot is lower than the high water mark it's from a stale + leader slot, because we will not become leader for the same slot twice + even if we are reset back in time (to prevent duplicate blocks). */ + int is_frag_for_prior_leader_slot = slothighwater_leader_slot; if( FD_UNLIKELY( ctx->in_kind[ in_idx ]==IN_KIND_PACK ) ) { /* We now know the real amount of microblocks published, so set an exact bound for once we receive them. */ ctx->skip_frag = 1; - if( pkt_type==POH_PKT_TYPE_DONE_PACKING ) { - if( FD_UNLIKELY( is_frag_for_prior_leader_slot ) ) return; - - FD_TEST( ctx->microblocks_lower_bound<=ctx->max_microblocks_per_slot ); - fd_done_packing_t const * done_packing = fd_chunk_to_laddr( ctx->in[ in_idx ].mem, chunk ); - FD_LOG_INFO(( "done_packing(slot=%lu,seen_microblocks=%lu,microblocks_in_slot=%lu)", - ctx->slot, - ctx->microblocks_lower_bound, - done_packing->microblocks_in_slot )); - ctx->microblocks_lower_bound += ctx->max_microblocks_per_slot - done_packing->microblocks_in_slot; - } + if( FD_UNLIKELY( is_frag_for_prior_leader_slot ) ) return; + + FD_TEST( ctx->microblocks_lower_bound<=ctx->max_microblocks_per_slot ); + fd_done_packing_t const * done_packing = fd_chunk_to_laddr( ctx->in[ in_idx ].mem, chunk ); + FD_LOG_INFO(( "done_packing(slot=%lu,seen_microblocks=%lu,microblocks_in_slot=%lu)", + ctx->slot, + ctx->microblocks_lower_bound, + done_packing->microblocks_in_slot )); + ctx->microblocks_lower_bound += ctx->max_microblocks_per_slot - done_packing->microblocks_in_slot; return; } else { if( FD_UNLIKELY( chunkin[ in_idx ].chunk0 || chunk>ctx->in[ in_idx ].wmark || sz>USHORT_MAX ) ) @@ -2245,6 +2231,7 @@ unprivileged_init( fd_topo_t * topo, ctx->lagged_consecutive_leader_start = tile->poh.lagged_consecutive_leader_start; ctx->expect_sequential_leader_slot = ULONG_MAX; + ctx->expect_pack_idx = 0U; ctx->microblocks_lower_bound = 0UL; ctx->max_active_descendant = 0UL; @@ -2328,7 +2315,7 @@ unprivileged_init( fd_topo_t * topo, if( !strcmp( link->name, "stake_out" ) ) { ctx->in_kind[ i ] = IN_KIND_STAKE; - } else if( !strcmp( link->name, "pack_bank" ) ) { + } else if( !strcmp( link->name, "pack_poh" ) ) { ctx->in_kind[ i ] = IN_KIND_PACK; } else if( !strcmp( link->name, "bank_poh" ) ) { ctx->in_kind[ i ] = IN_KIND_BANK;