@@ -221,6 +221,16 @@ fd_gui_ws_open( fd_gui_t * gui,
221221 FD_TEST ( !fd_http_server_ws_send ( gui -> http , ws_conn_id ) );
222222 }
223223
224+ /* todo .. temporary workaround to skip the blur until frontend boot
225+ screen lands */
226+ if ( FD_UNLIKELY ( gui -> summary .is_full_client ) ) {
227+ uchar prev = gui -> summary .startup_progress .phase ;
228+ gui -> summary .startup_progress .phase = FD_GUI_START_PROGRESS_TYPE_RUNNING ;
229+ fd_gui_printf_startup_progress ( gui );
230+ FD_TEST ( !fd_http_server_ws_send ( gui -> http , ws_conn_id ) );
231+ gui -> summary .startup_progress .phase = prev ;
232+ }
233+
224234 if ( FD_LIKELY ( gui -> block_engine .has_block_engine ) ) {
225235 fd_gui_printf_block_engine ( gui );
226236 FD_TEST ( !fd_http_server_ws_send ( gui -> http , ws_conn_id ) );
@@ -632,8 +642,7 @@ fd_gui_run_boot_progress( fd_gui_t * gui, long now ) {
632642 gui -> summary .boot_progress .phase = FD_GUI_BOOT_PROGRESS_TYPE_LOADING_INCREMENTAL_SNAPSHOT ;
633643 gui -> summary .boot_progress .loading_snapshot [ FD_GUI_BOOT_PROGRESS_INCREMENTAL_SNAPSHOT_IDX ].sample_time_nanos = now ;
634644 }
635- int slot_turbine_hist_full = gui -> summary .slots_max_turbine [ FD_GUI_TURBINE_SLOT_HISTORY_SZ - 1 ].slot != ULONG_MAX ;
636- if ( FD_UNLIKELY ( snapshot_phase == 12UL && slot_turbine_hist_full && gui -> summary .slot_completed != ULONG_MAX ) ) {
645+ if ( FD_UNLIKELY ( snapshot_phase == 12UL && gui -> summary .slots_max_turbine [ 0 ].slot != ULONG_MAX && gui -> summary .slot_completed != ULONG_MAX ) ) {
637646 gui -> summary .boot_progress .phase = FD_GUI_BOOT_PROGRESS_TYPE_CATCHING_UP ;
638647 gui -> summary .boot_progress .catching_up_time_nanos = now ;
639648 }
@@ -1344,56 +1353,49 @@ fd_gui_clear_slot( fd_gui_t * gui,
13441353 }
13451354}
13461355
1347- static void
1348- fd_gui_handle_leader_schedule ( fd_gui_t * gui ,
1349- ulong const * msg ,
1350- long now ) {
1351- ulong epoch = msg [ 0 ];
1352- ulong staked_cnt = msg [ 1 ];
1353- ulong start_slot = msg [ 2 ];
1354- ulong slot_cnt = msg [ 3 ];
1355- ulong excluded_stake = msg [ 4 ];
1356- ulong vote_keyed_lsched = msg [ 5 ];
1357-
1358- FD_TEST ( staked_cnt <=MAX_STAKED_LEADERS );
1359- FD_TEST ( slot_cnt <=MAX_SLOTS_PER_EPOCH );
1360-
1361- ulong idx = epoch % 2UL ;
1356+ void
1357+ fd_gui_handle_leader_schedule ( fd_gui_t * gui ,
1358+ fd_stake_weight_msg_t const * leader_schedule ,
1359+ long now ) {
1360+ FD_TEST ( leader_schedule -> staked_cnt <=MAX_STAKED_LEADERS );
1361+ FD_TEST ( leader_schedule -> slot_cnt <=MAX_SLOTS_PER_EPOCH );
1362+
1363+ ulong idx = leader_schedule -> epoch % 2UL ;
13621364 gui -> epoch .has_epoch [ idx ] = 1 ;
13631365
1364- gui -> epoch .epochs [ idx ].epoch = epoch ;
1365- gui -> epoch .epochs [ idx ].start_slot = start_slot ;
1366- gui -> epoch .epochs [ idx ].end_slot = start_slot + slot_cnt - 1 ; // end_slot is inclusive.
1367- gui -> epoch .epochs [ idx ].excluded_stake = excluded_stake ;
1366+ gui -> epoch .epochs [ idx ].epoch = leader_schedule -> epoch ;
1367+ gui -> epoch .epochs [ idx ].start_slot = leader_schedule -> start_slot ;
1368+ gui -> epoch .epochs [ idx ].end_slot = leader_schedule -> start_slot + leader_schedule -> slot_cnt - 1 ; // end_slot is inclusive.
1369+ gui -> epoch .epochs [ idx ].excluded_stake = leader_schedule -> excluded_stake ;
13681370 gui -> epoch .epochs [ idx ].my_total_slots = 0UL ;
13691371 gui -> epoch .epochs [ idx ].my_skipped_slots = 0UL ;
13701372
13711373 memset ( gui -> epoch .epochs [ idx ].rankings , (int )(UINT_MAX ), sizeof (gui -> epoch .epochs [ idx ].rankings ) );
13721374 memset ( gui -> epoch .epochs [ idx ].my_rankings , (int )(UINT_MAX ), sizeof (gui -> epoch .epochs [ idx ].my_rankings ) );
13731375
1374- gui -> epoch .epochs [ idx ].rankings_slot = start_slot ;
1376+ gui -> epoch .epochs [ idx ].rankings_slot = leader_schedule -> start_slot ;
13751377
1376- fd_vote_stake_weight_t const * stake_weights = fd_type_pun_const ( msg + 6UL ) ;
1377- memcpy ( gui -> epoch .epochs [ idx ].stakes , stake_weights , staked_cnt * sizeof (fd_vote_stake_weight_t ) );
1378+ fd_vote_stake_weight_t const * stake_weights = leader_schedule -> weights ;
1379+ fd_memcpy ( gui -> epoch .epochs [ idx ].stakes , stake_weights , leader_schedule -> staked_cnt * sizeof (fd_vote_stake_weight_t ) );
13781380
13791381 fd_epoch_leaders_delete ( fd_epoch_leaders_leave ( gui -> epoch .epochs [ idx ].lsched ) );
13801382 gui -> epoch .epochs [idx ].lsched = fd_epoch_leaders_join ( fd_epoch_leaders_new ( gui -> epoch .epochs [ idx ]._lsched ,
1381- epoch ,
1383+ leader_schedule -> epoch ,
13821384 gui -> epoch .epochs [ idx ].start_slot ,
1383- slot_cnt ,
1384- staked_cnt ,
1385+ leader_schedule -> slot_cnt ,
1386+ leader_schedule -> staked_cnt ,
13851387 gui -> epoch .epochs [ idx ].stakes ,
1386- excluded_stake ,
1387- vote_keyed_lsched ) );
1388+ leader_schedule -> excluded_stake ,
1389+ leader_schedule -> vote_keyed_lsched ) );
13881390
1389- if ( FD_UNLIKELY ( start_slot == 0UL ) ) {
1391+ if ( FD_UNLIKELY ( leader_schedule -> start_slot == 0UL ) ) {
13901392 gui -> epoch .epochs [ 0 ].start_time = now ;
13911393 } else {
13921394 gui -> epoch .epochs [ idx ].start_time = LONG_MAX ;
13931395
1394- for ( ulong i = 0UL ; i < fd_ulong_min ( start_slot - 1UL , FD_GUI_SLOTS_CNT ); i ++ ) {
1395- fd_gui_slot_t * slot = gui -> slots [ (start_slot - i ) % FD_GUI_SLOTS_CNT ];
1396- if ( FD_UNLIKELY ( slot -> slot != (start_slot - i ) ) ) break ;
1396+ for ( ulong i = 0UL ; i < fd_ulong_min ( leader_schedule -> start_slot - 1UL , FD_GUI_SLOTS_CNT ); i ++ ) {
1397+ fd_gui_slot_t * slot = gui -> slots [ (leader_schedule -> start_slot - i ) % FD_GUI_SLOTS_CNT ];
1398+ if ( FD_UNLIKELY ( slot -> slot != (leader_schedule -> start_slot - i ) ) ) break ;
13971399 else if ( FD_UNLIKELY ( slot -> skipped ) ) continue ;
13981400
13991401 gui -> epoch .epochs [ idx ].start_time = slot -> completed_time ;
@@ -1773,8 +1775,7 @@ fd_gui_handle_rooted_slot( fd_gui_t * gui,
17731775 if ( FD_UNLIKELY ( slot -> slot == ULONG_MAX ) ) break ;
17741776
17751777 if ( FD_UNLIKELY ( slot -> slot != parent_slot ) ) {
1776- FD_LOG_ERR (( "_slot %lu i %lu we expect parent_slot %lu got slot->slot %lu" , _slot , i , parent_slot , slot -> slot ));
1777- }
1778+ FD_LOG_ERR (( "_slot %lu i %lu we expect parent_slot %lu got slot->slot %lu" , _slot , i , parent_slot , slot -> slot )); }
17781779 if ( FD_UNLIKELY ( slot -> level >=FD_GUI_SLOT_LEVEL_ROOTED ) ) break ;
17791780
17801781 slot -> level = FD_GUI_SLOT_LEVEL_ROOTED ;
@@ -2069,7 +2070,8 @@ fd_gui_handle_tower_update( fd_gui_t * gui,
20692070 long now ) {
20702071 (void )now ;
20712072
2072- if ( FD_LIKELY ( gui -> summary .slot_rooted != tower -> root_slot ) ) {
2073+ /* rooted slot */
2074+ if ( FD_LIKELY ( tower -> root_slot != ULONG_MAX && gui -> summary .slot_rooted != tower -> root_slot ) ) {
20732075 /* Move any shred data up to and including _slot from staging array
20742076 to history array */
20752077 ulong start_slot = fd_ulong_if ( gui -> shreds .history_slot != ULONG_MAX , gui -> shreds .history_slot + 1UL , tower -> root_slot );
@@ -2112,11 +2114,71 @@ fd_gui_handle_tower_update( fd_gui_t * gui,
21122114 gui->shreds.staged_next_broadcast to keep it in the bounds of the
21132115 ring buffer */
21142116 gui -> shreds .staged_next_broadcast = fd_ulong_max ( gui -> shreds .staged_head , gui -> shreds .staged_next_broadcast );
2117+
2118+ gui -> summary .slot_rooted = tower -> root_slot ;
2119+ fd_gui_printf_root_slot ( gui );
2120+ fd_http_server_ws_broadcast ( gui -> http );
2121+
2122+ fd_gui_printf_slot ( gui , gui -> summary .slot_rooted );
2123+ fd_http_server_ws_broadcast ( gui -> http );
21152124 }
21162125
2117- gui -> summary .slot_rooted = tower -> root_slot ;
2118- fd_gui_printf_root_slot ( gui );
2119- fd_http_server_ws_broadcast ( gui -> http );
2126+ /* optimisitically confirmed slot */
2127+ if ( FD_UNLIKELY ( tower -> opt_confirmed_slot != ULONG_MAX ) ) {
2128+ /* Slot 0 is always rooted. No need to iterate all the way back to
2129+ i==_slot */
2130+ for ( ulong i = 0UL ; i < fd_ulong_min ( tower -> opt_confirmed_slot , FD_GUI_SLOTS_CNT ); i ++ ) {
2131+ ulong parent_slot = tower -> opt_confirmed_slot - i ;
2132+ ulong parent_idx = parent_slot % FD_GUI_SLOTS_CNT ;
2133+
2134+ fd_gui_slot_t * slot = gui -> slots [ parent_idx ];
2135+ if ( FD_UNLIKELY ( slot -> slot == ULONG_MAX ) ) break ;
2136+
2137+ if ( FD_UNLIKELY ( slot -> slot > parent_slot ) ) {
2138+ FD_LOG_ERR (( "_slot %lu i %lu we expect parent_slot %lu got slot->slot %lu" , tower -> opt_confirmed_slot , i , parent_slot , slot -> slot ));
2139+ } else if ( FD_UNLIKELY ( slot -> slot < parent_slot ) ) {
2140+ /* Slot not even replayed yet ... will come out as optimistically confirmed */
2141+ continue ;
2142+ }
2143+ if ( FD_UNLIKELY ( slot -> level >=FD_GUI_SLOT_LEVEL_ROOTED ) ) break ;
2144+
2145+ if ( FD_LIKELY ( slot -> level < FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED ) ) {
2146+ slot -> level = FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED ;
2147+ fd_gui_printf_slot ( gui , parent_slot );
2148+ fd_http_server_ws_broadcast ( gui -> http );
2149+ }
2150+ }
2151+
2152+ if ( FD_UNLIKELY ( gui -> summary .slot_optimistically_confirmed != ULONG_MAX && tower -> opt_confirmed_slot < gui -> summary .slot_optimistically_confirmed ) ) {
2153+ /* Optimistically confirmed slot went backwards ... mark some slots as no
2154+ longer optimistically confirmed. */
2155+ for ( ulong i = gui -> summary .slot_optimistically_confirmed ; i >=tower -> opt_confirmed_slot ; i -- ) {
2156+ fd_gui_slot_t * slot = gui -> slots [ i % FD_GUI_SLOTS_CNT ];
2157+ if ( FD_UNLIKELY ( slot -> slot == ULONG_MAX ) ) break ;
2158+ if ( FD_LIKELY ( slot -> slot == i ) ) {
2159+ /* It's possible for the optimistically confirmed slot to skip
2160+ backwards between two slots that we haven't yet replayed. In
2161+ that case we don't need to change anything, since they will
2162+ get marked properly when they get completed. */
2163+ slot -> level = FD_GUI_SLOT_LEVEL_COMPLETED ;
2164+ fd_gui_printf_slot ( gui , i );
2165+ fd_http_server_ws_broadcast ( gui -> http );
2166+ }
2167+ }
2168+ }
2169+
2170+ int slot_turbine_hist_full = gui -> summary .slots_max_turbine [ FD_GUI_TURBINE_SLOT_HISTORY_SZ - 1UL ].slot != ULONG_MAX ;
2171+ if ( FD_UNLIKELY ( gui -> summary .slot_caught_up == ULONG_MAX && slot_turbine_hist_full && gui -> summary .slots_max_turbine [ 0 ].slot < (tower -> opt_confirmed_slot + 3UL ) ) ) {
2172+ gui -> summary .slot_caught_up = tower -> opt_confirmed_slot + 4UL ;
2173+
2174+ fd_gui_printf_slot_caught_up ( gui );
2175+ fd_http_server_ws_broadcast ( gui -> http );
2176+ }
2177+
2178+ gui -> summary .slot_optimistically_confirmed = tower -> opt_confirmed_slot ;
2179+ fd_gui_printf_optimistically_confirmed_slot ( gui );
2180+ fd_http_server_ws_broadcast ( gui -> http );
2181+ }
21202182}
21212183
21222184void
@@ -2161,7 +2223,8 @@ fd_gui_plugin_message( fd_gui_t * gui,
21612223 break ;
21622224 }
21632225 case FD_PLUGIN_MSG_LEADER_SCHEDULE : {
2164- fd_gui_handle_leader_schedule ( gui , (ulong const * )msg , now );
2226+ FD_STATIC_ASSERT ( sizeof (fd_stake_weight_msg_t )== 6 * sizeof (ulong ), "sanity check" );
2227+ fd_gui_handle_leader_schedule ( gui , (fd_stake_weight_msg_t * )msg , now );
21652228 break ;
21662229 }
21672230 case FD_PLUGIN_MSG_SLOT_START : {
0 commit comments