@@ -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-   // } 
2236- 
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 ); 
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  );
2254+ 
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