@@ -229,6 +229,20 @@ fd_gui_ws_open( fd_gui_t * gui,
229229 FD_TEST ( !fd_http_server_ws_send ( gui -> http , ws_conn_id ) );
230230 }
231231
232+ /* todo .. temporary workaround to skip the blur until frontend boot
233+ screen lands */
234+ if ( FD_UNLIKELY ( gui -> summary .is_full_client ) ) {
235+ ulong real_mls = fd_ulong_if ( gui -> summary .catch_up_repair_sz > 0UL , gui -> summary .catch_up_repair [ 0 ], 0UL );
236+ uchar prev_phase = gui -> summary .startup_progress .phase ;
237+ ulong prev_mls = gui -> summary .startup_progress .startup_ledger_max_slot ;
238+ gui -> summary .startup_progress .phase = FD_GUI_START_PROGRESS_TYPE_RUNNING ;
239+ gui -> summary .startup_progress .startup_ledger_max_slot = real_mls ;
240+ fd_gui_printf_startup_progress ( gui );
241+ FD_TEST ( !fd_http_server_ws_send ( gui -> http , ws_conn_id ) );
242+ gui -> summary .startup_progress .phase = prev_phase ;
243+ gui -> summary .startup_progress .startup_ledger_max_slot = prev_mls ;
244+ }
245+
232246 if ( FD_LIKELY ( gui -> block_engine .has_block_engine ) ) {
233247 fd_gui_printf_block_engine ( gui );
234248 FD_TEST ( !fd_http_server_ws_send ( gui -> http , ws_conn_id ) );
@@ -1353,55 +1367,48 @@ fd_gui_clear_slot( fd_gui_t * gui,
13531367 return slot ;
13541368}
13551369
1356- static void
1357- fd_gui_handle_leader_schedule ( fd_gui_t * gui ,
1358- ulong const * msg ,
1359- long now ) {
1360- ulong epoch = msg [ 0 ];
1361- ulong staked_cnt = msg [ 1 ];
1362- ulong start_slot = msg [ 2 ];
1363- ulong slot_cnt = msg [ 3 ];
1364- ulong excluded_stake = msg [ 4 ];
1365- ulong vote_keyed_lsched = msg [ 5 ];
1366-
1367- FD_TEST ( staked_cnt <=MAX_STAKED_LEADERS );
1368- FD_TEST ( slot_cnt <=MAX_SLOTS_PER_EPOCH );
1369-
1370- ulong idx = epoch % 2UL ;
1370+ void
1371+ fd_gui_handle_leader_schedule ( fd_gui_t * gui ,
1372+ fd_stake_weight_msg_t const * leader_schedule ,
1373+ long now ) {
1374+ FD_TEST ( leader_schedule -> staked_cnt <=MAX_STAKED_LEADERS );
1375+ FD_TEST ( leader_schedule -> slot_cnt <=MAX_SLOTS_PER_EPOCH );
1376+
1377+ ulong idx = leader_schedule -> epoch % 2UL ;
13711378 gui -> epoch .has_epoch [ idx ] = 1 ;
13721379
1373- gui -> epoch .epochs [ idx ].epoch = epoch ;
1374- gui -> epoch .epochs [ idx ].start_slot = start_slot ;
1375- gui -> epoch .epochs [ idx ].end_slot = start_slot + slot_cnt - 1 ; // end_slot is inclusive.
1376- gui -> epoch .epochs [ idx ].excluded_stake = excluded_stake ;
1380+ gui -> epoch .epochs [ idx ].epoch = leader_schedule -> epoch ;
1381+ gui -> epoch .epochs [ idx ].start_slot = leader_schedule -> start_slot ;
1382+ gui -> epoch .epochs [ idx ].end_slot = leader_schedule -> start_slot + leader_schedule -> slot_cnt - 1 ; // end_slot is inclusive.
1383+ gui -> epoch .epochs [ idx ].excluded_stake = leader_schedule -> excluded_stake ;
13771384 gui -> epoch .epochs [ idx ].my_total_slots = 0UL ;
13781385 gui -> epoch .epochs [ idx ].my_skipped_slots = 0UL ;
13791386
13801387 memset ( gui -> epoch .epochs [ idx ].rankings , (int )(UINT_MAX ), sizeof (gui -> epoch .epochs [ idx ].rankings ) );
13811388 memset ( gui -> epoch .epochs [ idx ].my_rankings , (int )(UINT_MAX ), sizeof (gui -> epoch .epochs [ idx ].my_rankings ) );
13821389
1383- gui -> epoch .epochs [ idx ].rankings_slot = start_slot ;
1390+ gui -> epoch .epochs [ idx ].rankings_slot = leader_schedule -> start_slot ;
13841391
1385- fd_vote_stake_weight_t const * stake_weights = fd_type_pun_const ( msg + 6UL ) ;
1386- memcpy ( gui -> epoch .epochs [ idx ].stakes , stake_weights , staked_cnt * sizeof (fd_vote_stake_weight_t ) );
1392+ fd_vote_stake_weight_t const * stake_weights = leader_schedule -> weights ;
1393+ fd_memcpy ( gui -> epoch .epochs [ idx ].stakes , stake_weights , leader_schedule -> staked_cnt * sizeof (fd_vote_stake_weight_t ) );
13871394
13881395 fd_epoch_leaders_delete ( fd_epoch_leaders_leave ( gui -> epoch .epochs [ idx ].lsched ) );
13891396 gui -> epoch .epochs [idx ].lsched = fd_epoch_leaders_join ( fd_epoch_leaders_new ( gui -> epoch .epochs [ idx ]._lsched ,
1390- epoch ,
1397+ leader_schedule -> epoch ,
13911398 gui -> epoch .epochs [ idx ].start_slot ,
1392- slot_cnt ,
1393- staked_cnt ,
1399+ leader_schedule -> slot_cnt ,
1400+ leader_schedule -> staked_cnt ,
13941401 gui -> epoch .epochs [ idx ].stakes ,
1395- excluded_stake ,
1396- vote_keyed_lsched ) );
1402+ leader_schedule -> excluded_stake ,
1403+ leader_schedule -> vote_keyed_lsched ) );
13971404
1398- if ( FD_UNLIKELY ( start_slot == 0UL ) ) {
1405+ if ( FD_UNLIKELY ( leader_schedule -> start_slot == 0UL ) ) {
13991406 gui -> epoch .epochs [ 0 ].start_time = now ;
14001407 } else {
14011408 gui -> epoch .epochs [ idx ].start_time = LONG_MAX ;
14021409
1403- for ( ulong i = 0UL ; i < fd_ulong_min ( start_slot - 1UL , FD_GUI_SLOTS_CNT ); i ++ ) {
1404- fd_gui_slot_t const * slot = fd_gui_get_slot_const ( gui , start_slot - i );
1410+ for ( ulong i = 0UL ; i < fd_ulong_min ( leader_schedule -> start_slot - 1UL , FD_GUI_SLOTS_CNT ); i ++ ) {
1411+ fd_gui_slot_t const * slot = fd_gui_get_slot_const ( gui , leader_schedule -> start_slot - i );
14051412 if ( FD_UNLIKELY ( !slot ) ) break ;
14061413 else if ( FD_UNLIKELY ( slot -> skipped ) ) continue ;
14071414
@@ -1829,8 +1836,7 @@ fd_gui_handle_rooted_slot_legacy( fd_gui_t * gui,
18291836 if ( FD_UNLIKELY ( !slot ) ) break ;
18301837
18311838 if ( FD_UNLIKELY ( slot -> slot != parent_slot ) ) {
1832- FD_LOG_ERR (( "_slot %lu i %lu we expect parent_slot %lu got slot->slot %lu" , _slot , i , parent_slot , slot -> slot ));
1833- }
1839+ FD_LOG_ERR (( "_slot %lu i %lu we expect parent_slot %lu got slot->slot %lu" , _slot , i , parent_slot , slot -> slot )); }
18341840 if ( FD_UNLIKELY ( slot -> level >=FD_GUI_SLOT_LEVEL_ROOTED ) ) break ;
18351841
18361842 slot -> level = FD_GUI_SLOT_LEVEL_ROOTED ;
@@ -2072,6 +2078,11 @@ fd_gui_handle_reset_slot( fd_gui_t * gui, ulong reset_slot, long now ) {
20722078 ulong prev_slot_completed = gui -> summary .slot_completed ;
20732079 gui -> summary .slot_completed = reset_slot ;
20742080
2081+ if ( FD_LIKELY ( fd_gui_get_slot ( gui , gui -> summary .slot_completed ) ) ) {
2082+ fd_gui_printf_slot ( gui , gui -> summary .slot_completed );
2083+ fd_http_server_ws_broadcast ( gui -> http );
2084+ }
2085+
20752086 fd_gui_printf_completed_slot ( gui );
20762087 fd_http_server_ws_broadcast ( gui -> http );
20772088
@@ -2183,7 +2194,6 @@ fd_gui_handle_reset_slot( fd_gui_t * gui, ulong reset_slot, long now ) {
21832194
21842195static void
21852196fd_gui_handle_rooted_slot ( fd_gui_t * gui , ulong root_slot ) {
2186- // ulong unstaged_cnt = 0UL;
21872197 for ( ulong i = 0UL ; i < fd_ulong_min ( root_slot , FD_GUI_SLOTS_CNT ); i ++ ) {
21882198 ulong parent_slot = root_slot - i ;
21892199
@@ -2195,49 +2205,72 @@ fd_gui_handle_rooted_slot( fd_gui_t * gui, ulong root_slot ) {
21952205 }
21962206 if ( FD_UNLIKELY ( slot -> level >=FD_GUI_SLOT_LEVEL_ROOTED ) ) break ;
21972207
2198- /* TODO: commented out due to being too slow */
2199- // /* archive root shred events */
2200- // slot->shreds.start_offset = gui->shreds.history_tail;
2201- // for( ulong i=gui->shreds.staged_head; i<gui->shreds.staged_tail; i++ ) {
2202- // if( FD_UNLIKELY( gui->shreds.staged[ i ].slot==slot->slot ) ) {
2203- // /* move event to history */
2204- // gui->shreds.history[ gui->shreds.history_tail ].timestamp = gui->shreds.staged[ i ].timestamp;
2205- // gui->shreds.history[ gui->shreds.history_tail ].shred_idx = gui->shreds.staged[ i ].shred_idx;
2206- // gui->shreds.history[ gui->shreds.history_tail ].event = gui->shreds.staged[ i ].event;
2207- // gui->shreds.history_tail++;
2208-
2209- // gui->shreds.staged[ i ].slot = ULONG_MAX;
2210- // unstaged_cnt++;
2211- // }
2212-
2213- // /* evict older slots staged also */
2214- // if( FD_UNLIKELY( gui->shreds.staged[ i ].slot<slot->slot ) ) {
2215- // gui->shreds.staged[ i ].slot = ULONG_MAX;
2216- // unstaged_cnt++;
2217- // }
2218- // }
2219- // slot->shreds.end_offset = gui->shreds.history_tail;
2220-
2221- // /* change notarization levels and rebroadcast */
2222- // slot->level = FD_GUI_SLOT_LEVEL_ROOTED;
2223- // fd_gui_printf_slot( gui, parent_slot );
2224- // fd_http_server_ws_broadcast( gui->http );
2208+ /* change notarization levels and rebroadcast */
2209+ slot -> level = FD_GUI_SLOT_LEVEL_ROOTED ;
2210+ fd_gui_printf_slot ( gui , parent_slot );
2211+ fd_http_server_ws_broadcast ( gui -> http );
2212+ }
2213+
2214+ /* archive root shred events. We want to avoid n^2 iteration here
2215+ since it can significantly slow things down. Instead, we copy
2216+ over all rooted shreds to a scratch space, stable sort by slot,
2217+ copy the sorted arrays to the shred history. */
2218+ ulong evicted_cnt = 0UL ; /* the total number evicted, including ignored */
2219+ ulong archive_cnt = 0UL ; /* the total number evicted, NOT including ignored */
2220+ for ( ulong i = gui -> shreds .staged_head ; i < gui -> shreds .staged_tail ; i ++ ) {
2221+ /* ignore new shred events that came in after their slot was rooted */
2222+ if ( FD_UNLIKELY ( gui -> shreds .history_slot != ULONG_MAX && gui -> shreds .staged [ i ].slot <=gui -> shreds .history_slot ) ) {
2223+ gui -> shreds .staged [ i ].slot = ULONG_MAX ;
2224+ evicted_cnt ++ ;
2225+ }
2226+
2227+ if ( FD_UNLIKELY ( gui -> shreds .staged [ i ].slot <=root_slot ) ) {
2228+ /* move to scratch */
2229+ fd_memcpy ( gui -> shreds ._staged_scratch , & gui -> shreds .staged [ i ], sizeof (fd_gui_slot_staged_shred_event_t ) );
2230+ archive_cnt ++ ;
2231+
2232+ /* evict from staged */
2233+ gui -> shreds .staged [ i ].slot = ULONG_MAX ;
2234+ evicted_cnt ++ ;
2235+ }
22252236 }
22262237
22272238 /* The entries from the staging area are evicted by setting their
22282239 slot field to ULONG MAX, then sorting the staging area.
22292240
22302241 IMPORTANT: this sort needs to be stable since we always keep
22312242 valid un-broadcast events at the end of the ring buffer */
2232- // if( FD_LIKELY( unstaged_cnt ) ) {
2233- // fd_gui_slot_staged_shred_event_sort_insert( &gui->shreds.staged[ gui->shreds.staged_head ], gui->shreds.staged_tail-gui->shreds.staged_head );
2234- // gui->shreds.staged_head += unstaged_cnt;
2235- // }
2243+ if ( FD_LIKELY ( evicted_cnt ) ) {
2244+ fd_gui_slot_staged_shred_event_evict_sort_stable ( & gui -> shreds .staged [ gui -> shreds .staged_head ], gui -> shreds .staged_tail - gui -> shreds .staged_head , gui -> shreds ._staged_scratch2 );
2245+ gui -> shreds .staged_head += evicted_cnt ;
2246+
2247+ /* In the rare case that we are archiving any shred events that have
2248+ not yet been broadcast, we'll increment
2249+ gui->shreds.staged_next_broadcast to keep it in bounds. */
2250+ gui -> shreds .staged_next_broadcast = fd_ulong_max ( gui -> shreds .staged_head , gui -> shreds .staged_next_broadcast );
2251+
2252+ /* sort scratch by slot increasing */
2253+ fd_gui_slot_staged_shred_event_slot_sort_stable ( gui -> shreds ._staged_scratch , archive_cnt , gui -> shreds ._staged_scratch2 );
22362254
2237- // /* In the rare case that we are archiving any shred events that have
2238- // not yet been broadcast, we'll increment
2239- // gui->shreds.staged_next_broadcast to keep it in bounds. */
2240- // gui->shreds.staged_next_broadcast = fd_ulong_max( gui->shreds.staged_head, gui->shreds.staged_next_broadcast );
2255+ /* copy shred events to archive */
2256+ for ( ulong i = 0UL ; i < archive_cnt ; i ++ ) {
2257+ if ( FD_UNLIKELY ( gui -> shreds ._staged_scratch [ i ].slot != gui -> shreds .history_slot ) ) {
2258+ fd_gui_slot_t * prev_slot = fd_gui_get_slot ( gui , gui -> shreds .history_slot );
2259+ if ( FD_LIKELY ( prev_slot ) ) prev_slot -> shreds .end_offset = gui -> shreds .history_tail ;
2260+
2261+ gui -> shreds .history_slot = gui -> shreds ._staged_scratch [ i ].slot ;
2262+
2263+ fd_gui_slot_t * next_slot = fd_gui_get_slot ( gui , gui -> shreds .history_slot );
2264+ if ( FD_LIKELY ( next_slot ) ) next_slot -> shreds .start_offset = gui -> shreds .history_tail ;
2265+ }
2266+
2267+ gui -> shreds .history [ gui -> shreds .history_tail ].timestamp = gui -> shreds ._staged_scratch [ i ].timestamp ;
2268+ gui -> shreds .history [ gui -> shreds .history_tail ].shred_idx = gui -> shreds ._staged_scratch [ i ].shred_idx ;
2269+ gui -> shreds .history [ gui -> shreds .history_tail ].event = gui -> shreds ._staged_scratch [ i ].event ;
2270+
2271+ gui -> shreds .history_tail ++ ;
2272+ }
2273+ }
22412274
22422275 gui -> summary .slot_rooted = root_slot ;
22432276 fd_gui_printf_root_slot ( gui );
@@ -2365,7 +2398,8 @@ fd_gui_plugin_message( fd_gui_t * gui,
23652398 break ;
23662399 }
23672400 case FD_PLUGIN_MSG_LEADER_SCHEDULE : {
2368- fd_gui_handle_leader_schedule ( gui , (ulong const * )msg , now );
2401+ FD_STATIC_ASSERT ( sizeof (fd_stake_weight_msg_t )== 6 * sizeof (ulong ), "sanity check" );
2402+ fd_gui_handle_leader_schedule ( gui , (fd_stake_weight_msg_t * )msg , now );
23692403 break ;
23702404 }
23712405 case FD_PLUGIN_MSG_SLOT_START : {
0 commit comments