Line data Source code
1 : #ifndef HEADER_fd_src_disco_gui_fd_gui_printf_h
2 : #define HEADER_fd_src_disco_gui_fd_gui_printf_h
3 :
4 : #include <ctype.h>
5 : #include <stdio.h>
6 :
7 : #include "fd_gui_printf.h"
8 :
9 : #include "../../ballet/http/fd_http_server_private.h"
10 : #include "../../ballet/utf8/fd_utf8.h"
11 : #include "../../app/fdctl/version.h"
12 :
13 : static void
14 0 : jsonp_strip_trailing_comma( fd_gui_t * gui ) {
15 0 : if( FD_LIKELY( !gui->http->stage_err &&
16 0 : gui->http->stage_len>=1UL &&
17 0 : gui->http->oring[ (gui->http->stage_off%gui->http->oring_sz)+gui->http->stage_len-1UL ]==(uchar)',' ) ) {
18 0 : gui->http->stage_len--;
19 0 : }
20 0 : }
21 :
22 : static void
23 : jsonp_open_object( fd_gui_t * gui,
24 0 : char const * key ) {
25 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( gui->http, "\"%s\":{", key );
26 0 : else fd_http_server_printf( gui->http, "{" );
27 0 : }
28 :
29 : static void
30 0 : jsonp_close_object( fd_gui_t * gui ) {
31 0 : jsonp_strip_trailing_comma( gui );
32 0 : fd_http_server_printf( gui->http, "}," );
33 0 : }
34 :
35 : static void
36 : jsonp_open_array( fd_gui_t * gui,
37 0 : char const * key ) {
38 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( gui->http, "\"%s\":[", key );
39 0 : else fd_http_server_printf( gui->http, "[" );
40 0 : }
41 :
42 : static void
43 0 : jsonp_close_array( fd_gui_t * gui ) {
44 0 : jsonp_strip_trailing_comma( gui );
45 0 : fd_http_server_printf( gui->http, "]," );
46 0 : }
47 :
48 : static void
49 : jsonp_ulong( fd_gui_t * gui,
50 : char const * key,
51 0 : ulong value ) {
52 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( gui->http, "\"%s\":%lu,", key, value );
53 0 : else fd_http_server_printf( gui->http, "%lu,", value );
54 0 : }
55 :
56 : static void
57 : jsonp_long( fd_gui_t * gui,
58 : char const * key,
59 0 : long value ) {
60 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( gui->http, "\"%s\":%ld,", key, value );
61 0 : else fd_http_server_printf( gui->http, "%ld,", value );
62 0 : }
63 :
64 : static void
65 : jsonp_double( fd_gui_t * gui,
66 : char const * key,
67 0 : double value ) {
68 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( gui->http, "\"%s\":%.2f,", key, value );
69 0 : else fd_http_server_printf( gui->http, "%.2f,", value );
70 0 : }
71 :
72 : static void
73 : jsonp_sanitize_str( fd_http_server_t * http,
74 0 : ulong start_len ) {
75 : /* escape quotemark, reverse solidus, and control chars U+0000 through U+001F
76 : just replace with a space */
77 0 : uchar * data = http->oring;
78 0 : for( ulong i=start_len; i<http->stage_len; i++ ) {
79 0 : if( FD_UNLIKELY( data[ (http->stage_off%http->oring_sz)+i ] < 0x20 ||
80 0 : data[ (http->stage_off%http->oring_sz)+i ] == '"' ||
81 0 : data[ (http->stage_off%http->oring_sz)+i ] == '\\' ) ) {
82 0 : data[ (http->stage_off%http->oring_sz)+i ] = ' ';
83 0 : }
84 0 : }
85 0 : }
86 :
87 : static void
88 : jsonp_string( fd_gui_t * gui,
89 : char const * key,
90 0 : char const * value ) {
91 0 : char * val = (void *)value;
92 0 : if( FD_LIKELY( value ) ) {
93 0 : if( FD_UNLIKELY( !fd_utf8_verify( value, strlen( value ) ) )) {
94 0 : val = NULL;
95 0 : }
96 0 : }
97 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( gui->http, "\"%s\":", key );
98 0 : if( FD_LIKELY( val ) ) {
99 0 : fd_http_server_printf( gui->http, "\"" );
100 0 : ulong start_len = gui->http->stage_len;
101 0 : fd_http_server_printf( gui->http, "%s", val );
102 0 : jsonp_sanitize_str( gui->http, start_len );
103 0 : fd_http_server_printf( gui->http, "\"," );
104 0 : } else {
105 0 : fd_http_server_printf( gui->http, "null," );
106 0 : }
107 0 : }
108 :
109 : static void
110 : jsonp_bool( fd_gui_t * gui,
111 : char const * key,
112 0 : int value ) {
113 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( gui->http, "\"%s\":%s,", key, value ? "true" : "false" );
114 0 : else fd_http_server_printf( gui->http, "%s,", value ? "true" : "false" );
115 0 : }
116 :
117 : static void
118 : jsonp_null( fd_gui_t * gui,
119 0 : char const * key ) {
120 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( gui->http, "\"%s\": null,", key );
121 0 : else fd_http_server_printf( gui->http, "null," );
122 0 : }
123 :
124 : static void
125 : jsonp_open_envelope( fd_gui_t * gui,
126 : char const * topic,
127 0 : char const * key ) {
128 0 : jsonp_open_object( gui, NULL );
129 0 : jsonp_string( gui, "topic", topic );
130 0 : jsonp_string( gui, "key", key );
131 0 : }
132 :
133 : static void
134 0 : jsonp_close_envelope( fd_gui_t * gui ) {
135 0 : jsonp_close_object( gui );
136 0 : jsonp_strip_trailing_comma( gui );
137 0 : }
138 :
139 : void
140 : fd_gui_printf_open_query_response_envelope( fd_gui_t * gui,
141 : char const * topic,
142 : char const * key,
143 0 : ulong id ) {
144 0 : jsonp_open_object( gui, NULL );
145 0 : jsonp_string( gui, "topic", topic );
146 0 : jsonp_string( gui, "key", key );
147 0 : jsonp_ulong( gui, "id", id );
148 0 : }
149 :
150 : void
151 0 : fd_gui_printf_close_query_response_envelope( fd_gui_t * gui ) {
152 0 : jsonp_close_object( gui );
153 0 : jsonp_strip_trailing_comma( gui );
154 0 : }
155 :
156 : void
157 : fd_gui_printf_null_query_response( fd_gui_t * gui,
158 : char const * topic,
159 : char const * key,
160 0 : ulong id ) {
161 0 : fd_gui_printf_open_query_response_envelope( gui, topic, key, id );
162 0 : jsonp_null( gui, "value" );
163 0 : fd_gui_printf_close_query_response_envelope( gui );
164 0 : }
165 :
166 : void
167 0 : fd_gui_printf_version( fd_gui_t * gui ) {
168 0 : jsonp_open_envelope( gui, "summary", "version" );
169 0 : jsonp_string( gui, "value", gui->summary.version );
170 0 : jsonp_close_envelope( gui );
171 0 : }
172 :
173 : void
174 0 : fd_gui_printf_cluster( fd_gui_t * gui ) {
175 0 : jsonp_open_envelope( gui, "summary", "cluster" );
176 0 : jsonp_string( gui, "value", gui->summary.cluster );
177 0 : jsonp_close_envelope( gui );
178 0 : }
179 :
180 : void
181 0 : fd_gui_printf_commit_hash( fd_gui_t * gui ) {
182 0 : jsonp_open_envelope( gui, "summary", "commit_hash" );
183 0 : #ifdef FDCTL_COMMIT_REF_CSTR
184 0 : jsonp_string( gui, "value", FD_EXPAND_THEN_STRINGIFY(FDCTL_COMMIT_REF_CSTR) );
185 : #else
186 : jsonp_string( gui, "value", "0000000000000000000000000000000000000000" );
187 : #endif
188 0 : jsonp_close_envelope( gui );
189 0 : }
190 :
191 : void
192 0 : fd_gui_printf_identity_key( fd_gui_t * gui ) {
193 0 : jsonp_open_envelope( gui, "summary", "identity_key" );
194 0 : jsonp_string( gui, "value", gui->summary.identity_key_base58 );
195 0 : jsonp_close_envelope( gui );
196 0 : }
197 :
198 : void
199 0 : fd_gui_printf_uptime_nanos( fd_gui_t * gui ) {
200 0 : jsonp_open_envelope( gui, "summary", "uptime_nanos" );
201 0 : jsonp_ulong( gui, "value", (ulong)(fd_log_wallclock() - gui->summary.startup_time_nanos ) );
202 0 : jsonp_close_envelope( gui );
203 0 : }
204 :
205 : void
206 0 : fd_gui_printf_vote_distance( fd_gui_t * gui ) {
207 0 : jsonp_open_envelope( gui, "summary", "vote_distance" );
208 0 : jsonp_ulong( gui, "value", gui->summary.vote_distance );
209 0 : jsonp_close_envelope( gui );
210 0 : }
211 :
212 :
213 : void
214 0 : fd_gui_printf_vote_state( fd_gui_t * gui ) {
215 0 : jsonp_open_envelope( gui, "summary", "vote_state" );
216 0 : switch( gui->summary.vote_state ) {
217 0 : case FD_GUI_VOTE_STATE_NON_VOTING:
218 0 : jsonp_string( gui, "value", "non-voting" );
219 0 : break;
220 0 : case FD_GUI_VOTE_STATE_VOTING:
221 0 : jsonp_string( gui, "value", "voting" );
222 0 : break;
223 0 : case FD_GUI_VOTE_STATE_DELINQUENT:
224 0 : jsonp_string( gui, "value", "delinquent" );
225 0 : break;
226 0 : default:
227 0 : FD_LOG_ERR(( "unknown vote state %d", gui->summary.vote_state ));
228 0 : }
229 0 : jsonp_close_envelope( gui );
230 0 : }
231 :
232 : void
233 0 : fd_gui_printf_skipped_history( fd_gui_t * gui ) {
234 0 : jsonp_open_envelope( gui, "slot", "skipped_history" );
235 0 : jsonp_open_array( gui, "value" );
236 0 : for( ulong i=0UL; i<fd_ulong_min( gui->summary.slot_completed+1, FD_GUI_SLOTS_CNT ); i++ ) {
237 0 : ulong _slot = gui->summary.slot_completed-i;
238 0 : fd_gui_slot_t * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
239 :
240 0 : if( FD_UNLIKELY( slot->slot!=_slot ) ) break;
241 0 : if( FD_UNLIKELY( slot->mine && slot->skipped ) ) jsonp_ulong( gui, NULL, slot->slot );
242 0 : }
243 0 : jsonp_close_array( gui );
244 0 : jsonp_close_envelope( gui );
245 0 : }
246 :
247 : void
248 0 : fd_gui_printf_tps_history( fd_gui_t * gui ) {
249 0 : jsonp_open_envelope( gui, "summary", "tps_history" );
250 0 : jsonp_open_array( gui, "value" );
251 :
252 0 : for( ulong i=0UL; i<FD_GUI_TPS_HISTORY_SAMPLE_CNT; i++ ) {
253 0 : ulong idx = (gui->summary.estimated_tps_history_idx+i) % FD_GUI_TPS_HISTORY_SAMPLE_CNT;
254 0 : jsonp_open_array( gui, NULL );
255 0 : jsonp_double( gui, NULL, (double)gui->summary.estimated_tps_history[ idx ][ 0 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
256 0 : jsonp_double( gui, NULL, (double)gui->summary.estimated_tps_history[ idx ][ 1 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
257 0 : jsonp_double( gui, NULL, (double)(gui->summary.estimated_tps_history[ idx ][ 0 ] - gui->summary.estimated_tps_history[ idx ][ 1 ] - gui->summary.estimated_tps_history[ idx ][ 2 ])/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
258 0 : jsonp_double( gui, NULL, (double)gui->summary.estimated_tps_history[ idx ][ 2 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
259 0 : jsonp_close_array( gui );
260 0 : }
261 :
262 0 : jsonp_close_array( gui );
263 0 : jsonp_close_envelope( gui );
264 0 : }
265 :
266 : void
267 0 : fd_gui_printf_startup_progress( fd_gui_t * gui ) {
268 0 : char const * phase;
269 :
270 0 : switch( gui->summary.startup_progress ) {
271 0 : case FD_GUI_START_PROGRESS_TYPE_INITIALIZING:
272 0 : phase = "initializing";
273 0 : break;
274 0 : case FD_GUI_START_PROGRESS_TYPE_SEARCHING_FOR_FULL_SNAPSHOT:
275 0 : phase = "searching_for_full_snapshot";
276 0 : break;
277 0 : case FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT:
278 0 : phase = "downloading_full_snapshot";
279 0 : break;
280 0 : case FD_GUI_START_PROGRESS_TYPE_SEARCHING_FOR_INCREMENTAL_SNAPSHOT:
281 0 : phase = "searching_for_incremental_snapshot";
282 0 : break;
283 0 : case FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT:
284 0 : phase = "downloading_incremental_snapshot";
285 0 : break;
286 0 : case FD_GUI_START_PROGRESS_TYPE_CLEANING_BLOCK_STORE:
287 0 : phase = "cleaning_blockstore";
288 0 : break;
289 0 : case FD_GUI_START_PROGRESS_TYPE_CLEANING_ACCOUNTS:
290 0 : phase = "cleaning_accounts";
291 0 : break;
292 0 : case FD_GUI_START_PROGRESS_TYPE_LOADING_LEDGER:
293 0 : phase = "loading_ledger";
294 0 : break;
295 0 : case FD_GUI_START_PROGRESS_TYPE_PROCESSING_LEDGER:
296 0 : phase = "processing_ledger";
297 0 : break;
298 0 : case FD_GUI_START_PROGRESS_TYPE_STARTING_SERVICES:
299 0 : phase = "starting_services";
300 0 : break;
301 0 : case FD_GUI_START_PROGRESS_TYPE_HALTED:
302 0 : phase = "halted";
303 0 : break;
304 0 : case FD_GUI_START_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY:
305 0 : phase = "waiting_for_supermajority";
306 0 : break;
307 0 : case FD_GUI_START_PROGRESS_TYPE_RUNNING:
308 0 : phase = "running";
309 0 : break;
310 0 : default:
311 0 : FD_LOG_ERR(( "unknown phase %d", gui->summary.startup_progress ));
312 0 : }
313 :
314 0 : jsonp_open_envelope( gui, "summary", "startup_progress" );
315 0 : jsonp_open_object( gui, "value" );
316 0 : jsonp_string( gui, "phase", phase );
317 0 : if( FD_LIKELY( gui->summary.startup_progress>=FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT) ) {
318 0 : char peer_addr[ 64 ];
319 0 : FD_TEST( fd_cstr_printf_check( peer_addr, sizeof(peer_addr), NULL, FD_IP4_ADDR_FMT ":%u", FD_IP4_ADDR_FMT_ARGS(gui->summary.startup_full_snapshot_peer_ip_addr), gui->summary.startup_full_snapshot_peer_port ) );
320 :
321 0 : jsonp_string( gui, "downloading_full_snapshot_peer", peer_addr );
322 0 : jsonp_ulong( gui, "downloading_full_snapshot_slot", gui->summary.startup_full_snapshot_slot );
323 0 : jsonp_double( gui, "downloading_full_snapshot_elapsed_secs", gui->summary.startup_full_snapshot_elapsed_secs );
324 0 : jsonp_double( gui, "downloading_full_snapshot_remaining_secs", gui->summary.startup_full_snapshot_remaining_secs );
325 0 : jsonp_double( gui, "downloading_full_snapshot_throughput", gui->summary.startup_full_snapshot_throughput );
326 0 : jsonp_ulong( gui, "downloading_full_snapshot_total_bytes", gui->summary.startup_full_snapshot_total_bytes );
327 0 : jsonp_ulong( gui, "downloading_full_snapshot_current_bytes", gui->summary.startup_full_snapshot_current_bytes );
328 0 : } else {
329 0 : jsonp_null( gui, "downloading_full_snapshot_peer" );
330 0 : jsonp_null( gui, "downloading_full_snapshot_slot" );
331 0 : jsonp_null( gui, "downloading_full_snapshot_elapsed_secs" );
332 0 : jsonp_null( gui, "downloading_full_snapshot_remaining_secs" );
333 0 : jsonp_null( gui, "downloading_full_snapshot_throughput" );
334 0 : jsonp_null( gui, "downloading_full_snapshot_total_bytes" );
335 0 : jsonp_null( gui, "downloading_full_snapshot_current_bytes" );
336 0 : }
337 :
338 0 : if( FD_LIKELY( gui->summary.startup_progress>=FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT) ) {
339 0 : char peer_addr[ 64 ];
340 0 : FD_TEST( fd_cstr_printf_check( peer_addr, sizeof(peer_addr), NULL, FD_IP4_ADDR_FMT ":%u", FD_IP4_ADDR_FMT_ARGS(gui->summary.startup_incremental_snapshot_peer_ip_addr), gui->summary.startup_incremental_snapshot_peer_port ) );
341 :
342 0 : jsonp_string( gui, "downloading_incremental_snapshot_peer", peer_addr );
343 0 : jsonp_ulong( gui, "downloading_incremental_snapshot_slot", gui->summary.startup_incremental_snapshot_slot );
344 0 : jsonp_double( gui, "downloading_incremental_snapshot_elapsed_secs", gui->summary.startup_incremental_snapshot_elapsed_secs );
345 0 : jsonp_double( gui, "downloading_incremental_snapshot_remaining_secs", gui->summary.startup_incremental_snapshot_remaining_secs );
346 0 : jsonp_double( gui, "downloading_incremental_snapshot_throughput", gui->summary.startup_incremental_snapshot_throughput );
347 0 : jsonp_ulong( gui, "downloading_incremental_snapshot_total_bytes", gui->summary.startup_incremental_snapshot_total_bytes );
348 0 : jsonp_ulong( gui, "downloading_incremental_snapshot_current_bytes", gui->summary.startup_incremental_snapshot_current_bytes );
349 0 : } else {
350 0 : jsonp_null( gui, "downloading_incremental_snapshot_peer" );
351 0 : jsonp_null( gui, "downloading_incremental_snapshot_slot" );
352 0 : jsonp_null( gui, "downloading_incremental_snapshot_elapsed_secs" );
353 0 : jsonp_null( gui, "downloading_incremental_snapshot_remaining_secs" );
354 0 : jsonp_null( gui, "downloading_incremental_snapshot_throughput" );
355 0 : jsonp_null( gui, "downloading_incremental_snapshot_total_bytes" );
356 0 : jsonp_null( gui, "downloading_incremental_snapshot_current_bytes" );
357 0 : }
358 :
359 0 : if( FD_LIKELY( gui->summary.startup_progress>=FD_GUI_START_PROGRESS_TYPE_PROCESSING_LEDGER) ) {
360 0 : jsonp_ulong( gui, "ledger_slot", gui->summary.startup_ledger_slot );
361 0 : jsonp_ulong( gui, "ledger_max_slot", gui->summary.startup_ledger_max_slot );
362 0 : } else {
363 0 : jsonp_null( gui, "ledger_slot" );
364 0 : jsonp_null( gui, "ledger_max_slot" );
365 0 : }
366 :
367 0 : if( FD_LIKELY( gui->summary.startup_progress>=FD_GUI_START_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY ) && gui->summary.startup_waiting_for_supermajority_slot!=ULONG_MAX ) {
368 0 : jsonp_ulong( gui, "waiting_for_supermajority_slot", gui->summary.startup_waiting_for_supermajority_slot );
369 0 : jsonp_ulong( gui, "waiting_for_supermajority_stake_percent", gui->summary.startup_waiting_for_supermajority_stake_pct );
370 0 : } else {
371 0 : jsonp_null( gui, "waiting_for_supermajority_slot" );
372 0 : jsonp_null( gui, "waiting_for_supermajority_stake_percent" );
373 0 : }
374 0 : jsonp_close_object( gui );
375 0 : jsonp_close_envelope( gui );
376 0 : }
377 :
378 : void
379 0 : fd_gui_printf_block_engine( fd_gui_t * gui ) {
380 0 : jsonp_open_envelope( gui, "block_engine", "update" );
381 0 : jsonp_open_object( gui, "value" );
382 0 : jsonp_string( gui, "name", gui->block_engine.name );
383 0 : jsonp_string( gui, "url", gui->block_engine.url );
384 0 : if( FD_LIKELY( gui->block_engine.status==1 ) ) jsonp_string( gui, "status", "connecting" );
385 0 : else if( FD_LIKELY( gui->block_engine.status==2 ) ) jsonp_string( gui, "status", "connected" );
386 0 : else jsonp_string( gui, "status", "disconnected" );
387 0 : jsonp_close_object( gui );
388 0 : jsonp_close_envelope( gui );
389 0 : }
390 :
391 : void
392 0 : fd_gui_printf_tiles( fd_gui_t * gui ) {
393 0 : jsonp_open_envelope( gui, "summary", "tiles" );
394 0 : jsonp_open_array( gui, "value" );
395 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
396 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
397 :
398 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
399 : /* bench tiles not reported */
400 0 : continue;
401 0 : }
402 :
403 0 : jsonp_open_object( gui, NULL );
404 0 : jsonp_string( gui, "kind", tile->name );
405 0 : jsonp_ulong( gui, "kind_id", tile->kind_id );
406 0 : jsonp_close_object( gui );
407 0 : }
408 0 : jsonp_close_array( gui );
409 0 : jsonp_close_envelope( gui );
410 0 : }
411 :
412 :
413 : void
414 0 : fd_gui_printf_identity_balance( fd_gui_t * gui ) {
415 0 : jsonp_open_envelope( gui, "summary", "identity_balance" );
416 0 : jsonp_ulong( gui, "value", gui->summary.identity_account_balance );
417 0 : jsonp_close_envelope( gui );
418 0 : }
419 :
420 : void
421 0 : fd_gui_printf_vote_balance( fd_gui_t * gui ) {
422 0 : jsonp_open_envelope( gui, "summary", "vote_balance" );
423 0 : jsonp_ulong( gui, "value", gui->summary.vote_account_balance );
424 0 : jsonp_close_envelope( gui );
425 0 : }
426 :
427 : void
428 0 : fd_gui_printf_estimated_slot_duration_nanos( fd_gui_t * gui ) {
429 0 : jsonp_open_envelope( gui, "summary", "estimated_slot_duration_nanos" );
430 0 : jsonp_ulong( gui, "value", gui->summary.estimated_slot_duration_nanos );
431 0 : jsonp_close_envelope( gui );
432 0 : }
433 :
434 :
435 : void
436 0 : fd_gui_printf_root_slot( fd_gui_t * gui ) {
437 0 : jsonp_open_envelope( gui, "summary", "root_slot" );
438 0 : jsonp_ulong( gui, "value", gui->summary.slot_rooted );
439 0 : jsonp_close_envelope( gui );
440 0 : }
441 :
442 : void
443 0 : fd_gui_printf_optimistically_confirmed_slot( fd_gui_t * gui ) {
444 0 : jsonp_open_envelope( gui, "summary", "optimistically_confirmed_slot" );
445 0 : jsonp_ulong( gui, "value", gui->summary.slot_optimistically_confirmed );
446 0 : jsonp_close_envelope( gui );
447 0 : }
448 :
449 : void
450 0 : fd_gui_printf_completed_slot( fd_gui_t * gui ) {
451 0 : jsonp_open_envelope( gui, "summary", "completed_slot" );
452 0 : jsonp_ulong( gui, "value", gui->summary.slot_completed );
453 0 : jsonp_close_envelope( gui );
454 0 : }
455 :
456 : void
457 0 : fd_gui_printf_estimated_slot( fd_gui_t * gui ) {
458 0 : jsonp_open_envelope( gui, "summary", "estimated_slot" );
459 0 : jsonp_ulong( gui, "value", gui->summary.slot_estimated );
460 0 : jsonp_close_envelope( gui );
461 0 : }
462 :
463 : void
464 : fd_gui_printf_skip_rate( fd_gui_t * gui,
465 0 : ulong epoch_idx ) {
466 0 : jsonp_open_envelope( gui, "summary", "skip_rate" );
467 0 : jsonp_open_object( gui, "value" );
468 0 : jsonp_ulong( gui, "epoch", gui->epoch.epochs[ epoch_idx ].epoch );
469 0 : if( FD_UNLIKELY( !gui->epoch.epochs[ epoch_idx ].my_total_slots ) ) jsonp_double( gui, "skip_rate", 0.0 );
470 0 : else jsonp_double( gui, "skip_rate", (double)gui->epoch.epochs[ epoch_idx ].my_skipped_slots/(double)gui->epoch.epochs[ epoch_idx ].my_total_slots );
471 0 : jsonp_close_object( gui );
472 0 : jsonp_close_envelope( gui );
473 0 : }
474 :
475 : void
476 : fd_gui_printf_epoch( fd_gui_t * gui,
477 0 : ulong epoch_idx ) {
478 0 : jsonp_open_envelope( gui, "epoch", "new" );
479 0 : jsonp_open_object( gui, "value" );
480 0 : jsonp_ulong( gui, "epoch", gui->epoch.epochs[ epoch_idx ].epoch );
481 0 : if( FD_LIKELY( gui->epoch.epochs[ epoch_idx ].start_time!=LONG_MAX ) ) jsonp_ulong( gui, "start_time", (ulong)gui->epoch.epochs[ epoch_idx ].start_time );
482 0 : else jsonp_null( gui, "start_time" );
483 0 : if( FD_LIKELY( gui->epoch.epochs[ epoch_idx ].end_time!=LONG_MAX ) ) jsonp_ulong( gui, "end_time", (ulong)gui->epoch.epochs[ epoch_idx ].end_time );
484 0 : else jsonp_null( gui, "end_time" );
485 0 : jsonp_ulong( gui, "start_slot", gui->epoch.epochs[ epoch_idx ].start_slot );
486 0 : jsonp_ulong( gui, "end_slot", gui->epoch.epochs[ epoch_idx ].end_slot );
487 0 : jsonp_ulong( gui, "excluded_stake_lamports", gui->epoch.epochs[ epoch_idx ].excluded_stake );
488 0 : jsonp_open_array( gui, "staked_pubkeys" );
489 0 : fd_epoch_leaders_t * lsched = gui->epoch.epochs[epoch_idx].lsched;
490 0 : for( ulong i=0UL; i<lsched->pub_cnt; i++ ) {
491 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
492 0 : fd_base58_encode_32( lsched->pub[ i ].uc, NULL, identity_base58 );
493 0 : jsonp_string( gui, NULL, identity_base58 );
494 0 : }
495 0 : jsonp_close_array( gui );
496 :
497 0 : jsonp_open_array( gui, "staked_lamports" );
498 0 : fd_stake_weight_t * stakes = gui->epoch.epochs[epoch_idx].stakes;
499 0 : for( ulong i=0UL; i<lsched->pub_cnt; i++ ) jsonp_ulong( gui, NULL, stakes[ i ].stake );
500 0 : jsonp_close_array( gui );
501 :
502 0 : jsonp_open_array( gui, "leader_slots" );
503 0 : for( ulong i = 0; i < lsched->sched_cnt; i++ ) jsonp_ulong( gui, NULL, lsched->sched[ i ] );
504 0 : jsonp_close_array( gui );
505 0 : jsonp_close_object( gui );
506 0 : jsonp_close_envelope( gui );
507 0 : }
508 :
509 : static void
510 : fd_gui_printf_waterfall( fd_gui_t * gui,
511 : fd_gui_txn_waterfall_t const * prev,
512 0 : fd_gui_txn_waterfall_t const * cur ) {
513 0 : jsonp_open_object( gui, "waterfall" );
514 0 : jsonp_open_object( gui, "in" );
515 0 : jsonp_ulong( gui, "pack_cranked", cur->in.pack_cranked - prev->in.pack_cranked );
516 0 : jsonp_ulong( gui, "pack_retained", prev->out.pack_retained );
517 0 : jsonp_ulong( gui, "resolv_retained", prev->out.resolv_retained );
518 0 : jsonp_ulong( gui, "quic", cur->in.quic - prev->in.quic );
519 0 : jsonp_ulong( gui, "udp", cur->in.udp - prev->in.udp );
520 0 : jsonp_ulong( gui, "gossip", cur->in.gossip - prev->in.gossip );
521 0 : jsonp_ulong( gui, "block_engine", cur->in.block_engine - prev->in.block_engine );
522 0 : jsonp_close_object( gui );
523 :
524 0 : jsonp_open_object( gui, "out" );
525 0 : jsonp_ulong( gui, "net_overrun", cur->out.net_overrun - prev->out.net_overrun );
526 0 : jsonp_ulong( gui, "quic_overrun", cur->out.quic_overrun - prev->out.quic_overrun );
527 0 : jsonp_ulong( gui, "quic_frag_drop", cur->out.quic_frag_drop - prev->out.quic_frag_drop );
528 0 : jsonp_ulong( gui, "quic_abandoned", cur->out.quic_abandoned - prev->out.quic_abandoned );
529 0 : jsonp_ulong( gui, "tpu_quic_invalid", cur->out.tpu_quic_invalid - prev->out.tpu_quic_invalid );
530 0 : jsonp_ulong( gui, "tpu_udp_invalid", cur->out.tpu_udp_invalid - prev->out.tpu_udp_invalid );
531 0 : jsonp_ulong( gui, "verify_overrun", cur->out.verify_overrun - prev->out.verify_overrun );
532 0 : jsonp_ulong( gui, "verify_parse", cur->out.verify_parse - prev->out.verify_parse );
533 0 : jsonp_ulong( gui, "verify_failed", cur->out.verify_failed - prev->out.verify_failed );
534 0 : jsonp_ulong( gui, "verify_duplicate", cur->out.verify_duplicate - prev->out.verify_duplicate );
535 0 : jsonp_ulong( gui, "dedup_duplicate", cur->out.dedup_duplicate - prev->out.dedup_duplicate );
536 0 : jsonp_ulong( gui, "resolv_lut_failed", cur->out.resolv_lut_failed - prev->out.resolv_lut_failed );
537 0 : jsonp_ulong( gui, "resolv_expired", cur->out.resolv_expired - prev->out.resolv_expired );
538 0 : jsonp_ulong( gui, "resolv_ancient", cur->out.resolv_ancient - prev->out.resolv_ancient );
539 0 : jsonp_ulong( gui, "resolv_no_ledger", cur->out.resolv_no_ledger - prev->out.resolv_no_ledger );
540 0 : jsonp_ulong( gui, "resolv_retained", cur->out.resolv_retained );
541 0 : jsonp_ulong( gui, "pack_invalid", cur->out.pack_invalid - prev->out.pack_invalid );
542 0 : jsonp_ulong( gui, "pack_expired", cur->out.pack_expired - prev->out.pack_expired );
543 0 : jsonp_ulong( gui, "pack_retained", cur->out.pack_retained );
544 0 : jsonp_ulong( gui, "pack_wait_full", cur->out.pack_wait_full - prev->out.pack_wait_full );
545 0 : jsonp_ulong( gui, "pack_leader_slow", cur->out.pack_leader_slow - prev->out.pack_leader_slow );
546 0 : jsonp_ulong( gui, "bank_invalid", cur->out.bank_invalid - prev->out.bank_invalid );
547 0 : jsonp_ulong( gui, "block_success", cur->out.block_success - prev->out.block_success );
548 0 : jsonp_ulong( gui, "block_fail", cur->out.block_fail - prev->out.block_fail );
549 0 : jsonp_close_object( gui );
550 0 : jsonp_close_object( gui );
551 0 : }
552 :
553 : void
554 : fd_gui_printf_live_txn_waterfall( fd_gui_t * gui,
555 : fd_gui_txn_waterfall_t const * prev,
556 : fd_gui_txn_waterfall_t const * cur,
557 0 : ulong next_leader_slot ) {
558 0 : jsonp_open_envelope( gui, "summary", "live_txn_waterfall" );
559 0 : jsonp_open_object( gui, "value" );
560 0 : jsonp_ulong( gui, "next_leader_slot", next_leader_slot );
561 0 : fd_gui_printf_waterfall( gui, prev, cur );
562 0 : jsonp_close_object( gui );
563 0 : jsonp_close_envelope( gui );
564 0 : }
565 :
566 : static void
567 : fd_gui_printf_tile_stats( fd_gui_t * gui,
568 : fd_gui_tile_stats_t const * prev,
569 0 : fd_gui_tile_stats_t const * cur ) {
570 0 : jsonp_open_object( gui, "tile_primary_metric" );
571 0 : jsonp_ulong( gui, "quic", cur->quic_conn_cnt );
572 0 : if( FD_LIKELY( cur->sample_time_nanos>prev->sample_time_nanos ) ) {
573 0 : jsonp_ulong( gui, "net_in", (ulong)((double)(cur->net_in_rx_bytes - prev->net_in_rx_bytes) * 1000000000.0 / (double)(cur->sample_time_nanos - prev->sample_time_nanos) ));
574 0 : jsonp_ulong( gui, "net_out", (ulong)((double)(cur->net_out_tx_bytes - prev->net_out_tx_bytes) * 1000000000.0 / (double)(cur->sample_time_nanos - prev->sample_time_nanos) ));
575 0 : } else {
576 0 : jsonp_ulong( gui, "net_in", 0 );
577 0 : jsonp_ulong( gui, "net_out", 0 );
578 0 : }
579 0 : if( FD_LIKELY( cur->verify_total_cnt>prev->verify_total_cnt ) ) {
580 0 : jsonp_double( gui, "verify", (double)(cur->verify_drop_cnt-prev->verify_drop_cnt) / (double)(cur->verify_total_cnt-prev->verify_total_cnt) );
581 0 : } else {
582 0 : jsonp_double( gui, "verify", 0.0 );
583 0 : }
584 0 : if( FD_LIKELY( cur->dedup_total_cnt>prev->dedup_total_cnt ) ) {
585 0 : jsonp_double( gui, "dedup", (double)(cur->dedup_drop_cnt-prev->dedup_drop_cnt) / (double)(cur->dedup_total_cnt-prev->dedup_total_cnt) );
586 0 : } else {
587 0 : jsonp_double( gui, "dedup", 0.0 );
588 0 : }
589 0 : jsonp_ulong( gui, "bank", cur->bank_txn_exec_cnt - prev->bank_txn_exec_cnt );
590 0 : jsonp_double( gui, "pack", !cur->pack_buffer_capacity ? 1.0 : (double)cur->pack_buffer_cnt/(double)cur->pack_buffer_capacity );
591 0 : jsonp_double( gui, "poh", 0.0 );
592 0 : jsonp_double( gui, "shred", 0.0 );
593 0 : jsonp_double( gui, "store", 0.0 );
594 0 : jsonp_close_object( gui );
595 0 : }
596 :
597 : void
598 : fd_gui_printf_live_tile_stats( fd_gui_t * gui,
599 : fd_gui_tile_stats_t const * prev,
600 0 : fd_gui_tile_stats_t const * cur ) {
601 0 : jsonp_open_envelope( gui, "summary", "live_tile_primary_metric" );
602 0 : jsonp_open_object( gui, "value" );
603 0 : jsonp_ulong( gui, "next_leader_slot", 0UL );
604 0 : fd_gui_printf_tile_stats( gui, prev, cur );
605 0 : jsonp_close_object( gui );
606 0 : jsonp_close_envelope( gui );
607 0 : }
608 :
609 : static void
610 : fd_gui_printf_tile_timers( fd_gui_t * gui,
611 : fd_gui_tile_timers_t const * prev,
612 0 : fd_gui_tile_timers_t const * cur ) {
613 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
614 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
615 :
616 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
617 : /* bench tiles not reported */
618 0 : continue;
619 0 : }
620 :
621 0 : double cur_total = (double)(cur[ i ].caughtup_housekeeping_ticks
622 0 : + cur[ i ].processing_housekeeping_ticks
623 0 : + cur[ i ].backpressure_housekeeping_ticks
624 0 : + cur[ i ].caughtup_prefrag_ticks
625 0 : + cur[ i ].processing_prefrag_ticks
626 0 : + cur[ i ].backpressure_prefrag_ticks
627 0 : + cur[ i ].caughtup_postfrag_ticks
628 0 : + cur[ i ].processing_postfrag_ticks);
629 :
630 0 : double prev_total = (double)(prev[ i ].caughtup_housekeeping_ticks
631 0 : + prev[ i ].processing_housekeeping_ticks
632 0 : + prev[ i ].backpressure_housekeeping_ticks
633 0 : + prev[ i ].caughtup_prefrag_ticks
634 0 : + prev[ i ].processing_prefrag_ticks
635 0 : + prev[ i ].backpressure_prefrag_ticks
636 0 : + prev[ i ].caughtup_postfrag_ticks
637 0 : + prev[ i ].processing_postfrag_ticks);
638 :
639 0 : double idle;
640 0 : if( FD_UNLIKELY( cur_total==prev_total ) ) {
641 : /* The tile didn't sample timers since the last sample, unclear what
642 : idleness should be so send -1. NaN would be better but no NaN in
643 : JSON. */
644 0 : idle = -1;
645 0 : } else {
646 0 : idle = (double)(cur[ i ].caughtup_postfrag_ticks - prev[ i ].caughtup_postfrag_ticks) / (cur_total - prev_total);
647 0 : }
648 :
649 0 : jsonp_double( gui, NULL, idle );
650 0 : }
651 0 : }
652 :
653 : void
654 0 : fd_gui_printf_live_tile_timers( fd_gui_t * gui ) {
655 0 : jsonp_open_envelope( gui, "summary", "live_tile_timers" );
656 0 : jsonp_open_array( gui, "value" );
657 0 : fd_gui_tile_timers_t * cur = gui->summary.tile_timers_snap[ (gui->summary.tile_timers_snap_idx+(FD_GUI_TILE_TIMER_SNAP_CNT-1UL))%FD_GUI_TILE_TIMER_SNAP_CNT ];
658 0 : fd_gui_tile_timers_t * prev = gui->summary.tile_timers_snap[ (gui->summary.tile_timers_snap_idx+(FD_GUI_TILE_TIMER_SNAP_CNT-2UL))%FD_GUI_TILE_TIMER_SNAP_CNT ];
659 0 : fd_gui_printf_tile_timers( gui, prev, cur );
660 0 : jsonp_close_array( gui );
661 0 : jsonp_close_envelope( gui );
662 0 : }
663 :
664 : void
665 0 : fd_gui_printf_estimated_tps( fd_gui_t * gui ) {
666 0 : ulong idx = (gui->summary.estimated_tps_history_idx+FD_GUI_TPS_HISTORY_SAMPLE_CNT-1UL) % FD_GUI_TPS_HISTORY_SAMPLE_CNT;
667 :
668 0 : jsonp_open_envelope( gui, "summary", "estimated_tps" );
669 0 : jsonp_open_object( gui, "value" );
670 0 : jsonp_double( gui, "total", (double)gui->summary.estimated_tps_history[ idx ][ 0 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
671 0 : jsonp_double( gui, "vote", (double)gui->summary.estimated_tps_history[ idx ][ 1 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
672 0 : jsonp_double( gui, "nonvote_success", (double)(gui->summary.estimated_tps_history[ idx ][ 0 ] - gui->summary.estimated_tps_history[ idx ][ 1 ] - gui->summary.estimated_tps_history[ idx ][ 2 ])/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
673 0 : jsonp_double( gui, "nonvote_failed", (double)gui->summary.estimated_tps_history[ idx ][ 2 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
674 0 : jsonp_close_object( gui );
675 0 : jsonp_close_envelope( gui );
676 0 : }
677 :
678 : static int
679 : fd_gui_gossip_contains( fd_gui_t const * gui,
680 0 : uchar const * pubkey ) {
681 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
682 0 : if( FD_UNLIKELY( !memcmp( gui->gossip.peers[ i ].pubkey->uc, pubkey, 32 ) ) ) return 1;
683 0 : }
684 0 : return 0;
685 0 : }
686 :
687 : static int
688 : fd_gui_vote_acct_contains( fd_gui_t const * gui,
689 0 : uchar const * pubkey ) {
690 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
691 0 : if( FD_UNLIKELY( !memcmp( gui->vote_account.vote_accounts[ i ].pubkey, pubkey, 32 ) ) ) return 1;
692 0 : }
693 0 : return 0;
694 0 : }
695 :
696 : static int
697 : fd_gui_validator_info_contains( fd_gui_t const * gui,
698 0 : uchar const * pubkey ) {
699 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
700 0 : if( FD_UNLIKELY( !memcmp( gui->validator_info.info[ i ].pubkey, pubkey, 32 ) ) ) return 1;
701 0 : }
702 0 : return 0;
703 0 : }
704 :
705 : static void
706 : fd_gui_printf_peer( fd_gui_t * gui,
707 0 : uchar const * identity_pubkey ) {
708 0 : ulong gossip_idx = ULONG_MAX;
709 0 : ulong info_idx = ULONG_MAX;
710 0 : ulong vote_idxs[ 40200 ] = {0};
711 0 : ulong vote_idx_cnt = 0UL;
712 :
713 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
714 0 : if( FD_UNLIKELY( !memcmp( gui->gossip.peers[ i ].pubkey->uc, identity_pubkey, 32 ) ) ) {
715 0 : gossip_idx = i;
716 0 : break;
717 0 : }
718 0 : }
719 :
720 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
721 0 : if( FD_UNLIKELY( !memcmp( gui->validator_info.info[ i ].pubkey, identity_pubkey, 32 ) ) ) {
722 0 : info_idx = i;
723 0 : break;
724 0 : }
725 0 : }
726 :
727 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
728 0 : if( FD_UNLIKELY( !memcmp( gui->vote_account.vote_accounts[ i ].pubkey, identity_pubkey, 32 ) ) ) {
729 0 : vote_idxs[ vote_idx_cnt++ ] = i;
730 0 : }
731 0 : }
732 :
733 0 : jsonp_open_object( gui, NULL );
734 :
735 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
736 0 : fd_base58_encode_32( identity_pubkey, NULL, identity_base58 );
737 0 : jsonp_string( gui, "identity_pubkey", identity_base58 );
738 :
739 0 : if( FD_UNLIKELY( gossip_idx==ULONG_MAX ) ) {
740 0 : jsonp_string( gui, "gossip", NULL );
741 0 : } else {
742 0 : jsonp_open_object( gui, "gossip" );
743 :
744 0 : char version[ 32 ];
745 0 : FD_TEST( fd_cstr_printf( version, sizeof( version ), NULL, "%u.%u.%u", gui->gossip.peers[ gossip_idx ].version.major, gui->gossip.peers[ gossip_idx ].version.minor, gui->gossip.peers[ gossip_idx ].version.patch ) );
746 0 : jsonp_string( gui, "version", version );
747 0 : jsonp_ulong( gui, "feature_set", gui->gossip.peers[ gossip_idx ].version.feature_set );
748 0 : jsonp_ulong( gui, "wallclock", gui->gossip.peers[ gossip_idx ].wallclock );
749 0 : jsonp_ulong( gui, "shred_version", gui->gossip.peers[ gossip_idx ].shred_version );
750 0 : jsonp_open_object( gui, "sockets" );
751 0 : for( ulong j=0UL; j<12UL; j++ ) {
752 0 : if( FD_LIKELY( !gui->gossip.peers[ gossip_idx ].sockets[ j ].ipv4 && !gui->gossip.peers[ gossip_idx ].sockets[ j ].port ) ) continue;
753 0 : char const * tag;
754 0 : switch( j ) {
755 0 : case 0: tag = "gossip"; break;
756 0 : case 1: tag = "rpc"; break;
757 0 : case 2: tag = "rpb_pubsub"; break;
758 0 : case 3: tag = "serve_repair"; break;
759 0 : case 4: tag = "serve_repair_quic"; break;
760 0 : case 5: tag = "tpu"; break;
761 0 : case 6: tag = "tpu_quic"; break;
762 0 : case 7: tag = "tvu"; break;
763 0 : case 8: tag = "tvu_quic"; break;
764 0 : case 9: tag = "tpu_forwards"; break;
765 0 : case 10: tag = "tpu_forwards_quic"; break;
766 0 : case 11: tag = "tpu_vote"; break;
767 0 : }
768 0 : char line[ 64 ];
769 0 : FD_TEST( fd_cstr_printf( line, sizeof( line ), NULL, FD_IP4_ADDR_FMT ":%u", FD_IP4_ADDR_FMT_ARGS(gui->gossip.peers[ gossip_idx ].sockets[ j ].ipv4 ), gui->gossip.peers[ gossip_idx ].sockets[ j ].port ) );
770 0 : jsonp_string( gui, tag, line );
771 0 : }
772 0 : jsonp_close_object( gui );
773 :
774 0 : jsonp_close_object( gui );
775 0 : }
776 :
777 0 : jsonp_open_array( gui, "vote" );
778 0 : for( ulong i=0UL; i<vote_idx_cnt; i++ ) {
779 0 : jsonp_open_object( gui, NULL );
780 0 : char vote_account_base58[ FD_BASE58_ENCODED_32_SZ ];
781 0 : fd_base58_encode_32( gui->vote_account.vote_accounts[ vote_idxs[ i ] ].vote_account->uc, NULL, vote_account_base58 );
782 0 : jsonp_string( gui, "vote_account", vote_account_base58 );
783 0 : jsonp_ulong( gui, "activated_stake", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].activated_stake );
784 0 : jsonp_ulong( gui, "last_vote", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].last_vote );
785 0 : jsonp_ulong( gui, "root_slot", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].root_slot );
786 0 : jsonp_ulong( gui, "epoch_credits", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].epoch_credits );
787 0 : jsonp_ulong( gui, "commission", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].commission );
788 0 : jsonp_bool( gui, "delinquent", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].delinquent );
789 0 : jsonp_close_object( gui );
790 0 : }
791 0 : jsonp_close_array( gui );
792 :
793 0 : if( FD_UNLIKELY( info_idx==ULONG_MAX ) ) {
794 0 : jsonp_string( gui, "info", NULL );
795 0 : } else {
796 0 : jsonp_open_object( gui, "info" );
797 0 : jsonp_string( gui, "name", gui->validator_info.info[ info_idx ].name );
798 0 : jsonp_string( gui, "details", gui->validator_info.info[ info_idx ].details );
799 0 : jsonp_string( gui, "website", gui->validator_info.info[ info_idx ].website );
800 0 : jsonp_string( gui, "icon_url", gui->validator_info.info[ info_idx ].icon_uri );
801 0 : jsonp_close_object( gui );
802 0 : }
803 :
804 0 : jsonp_close_object( gui );
805 0 : }
806 :
807 : void
808 : fd_gui_printf_peers_gossip_update( fd_gui_t * gui,
809 : ulong const * updated,
810 : ulong updated_cnt,
811 : fd_pubkey_t const * removed,
812 : ulong removed_cnt,
813 : ulong const * added,
814 0 : ulong added_cnt ) {
815 0 : jsonp_open_envelope( gui, "peers", "update" );
816 0 : jsonp_open_object( gui, "value" );
817 0 : jsonp_open_array( gui, "add" );
818 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
819 0 : int actually_added = !fd_gui_vote_acct_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc ) &&
820 0 : !fd_gui_validator_info_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
821 0 : if( FD_LIKELY( !actually_added ) ) continue;
822 :
823 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
824 0 : }
825 0 : jsonp_close_array( gui );
826 :
827 0 : jsonp_open_array( gui, "update" );
828 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
829 0 : int actually_added = !fd_gui_vote_acct_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc ) &&
830 0 : !fd_gui_validator_info_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
831 0 : if( FD_LIKELY( actually_added ) ) continue;
832 :
833 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
834 0 : }
835 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
836 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ updated[ i ] ].pubkey->uc );
837 0 : }
838 0 : jsonp_close_array( gui );
839 :
840 0 : jsonp_open_array( gui, "remove" );
841 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
842 0 : int actually_removed = !fd_gui_vote_acct_contains( gui, removed[ i ].uc ) &&
843 0 : !fd_gui_validator_info_contains( gui, removed[ i ].uc );
844 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
845 :
846 0 : jsonp_open_object( gui, NULL );
847 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
848 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
849 0 : jsonp_string( gui, "identity_pubkey", identity_base58 );
850 0 : jsonp_close_object( gui );
851 0 : }
852 0 : jsonp_close_array( gui );
853 0 : jsonp_close_object( gui );
854 0 : jsonp_close_envelope( gui );
855 0 : }
856 :
857 : void
858 : fd_gui_printf_peers_vote_account_update( fd_gui_t * gui,
859 : ulong const * updated,
860 : ulong updated_cnt,
861 : fd_pubkey_t const * removed,
862 : ulong removed_cnt,
863 : ulong const * added,
864 0 : ulong added_cnt ) {
865 0 : jsonp_open_envelope( gui, "peers", "update" );
866 0 : jsonp_open_object( gui, "value" );
867 0 : jsonp_open_array( gui, "add" );
868 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
869 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
870 0 : !fd_gui_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
871 0 : if( FD_LIKELY( !actually_added ) ) continue;
872 :
873 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
874 0 : }
875 0 : jsonp_close_array( gui );
876 :
877 0 : jsonp_open_array( gui, "update" );
878 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
879 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
880 0 : !fd_gui_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
881 0 : if( FD_LIKELY( actually_added ) ) continue;
882 :
883 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
884 0 : }
885 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
886 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ updated[ i ] ].pubkey->uc );
887 0 : }
888 0 : jsonp_close_array( gui );
889 :
890 0 : jsonp_open_array( gui, "remove" );
891 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
892 0 : int actually_removed = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
893 0 : !fd_gui_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
894 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
895 :
896 0 : jsonp_open_object( gui, NULL );
897 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
898 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
899 0 : jsonp_string( gui, "identity_pubkey", identity_base58 );
900 0 : jsonp_close_object( gui );
901 0 : }
902 0 : jsonp_close_array( gui );
903 0 : jsonp_close_object( gui );
904 0 : jsonp_close_envelope( gui );
905 0 : }
906 :
907 : void
908 : fd_gui_printf_peers_validator_info_update( fd_gui_t * gui,
909 : ulong const * updated,
910 : ulong updated_cnt,
911 : fd_pubkey_t const * removed,
912 : ulong removed_cnt,
913 : ulong const * added,
914 0 : ulong added_cnt ) {
915 0 : jsonp_open_envelope( gui, "peers", "update" );
916 0 : jsonp_open_object( gui, "value" );
917 0 : jsonp_open_array( gui, "add" );
918 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
919 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
920 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
921 0 : if( FD_LIKELY( !actually_added ) ) continue;
922 :
923 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
924 0 : }
925 0 : jsonp_close_array( gui );
926 :
927 0 : jsonp_open_array( gui, "update" );
928 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
929 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
930 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
931 0 : if( FD_LIKELY( actually_added ) ) continue;
932 :
933 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
934 0 : }
935 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
936 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ updated[ i ] ].pubkey->uc );
937 0 : }
938 0 : jsonp_close_array( gui );
939 :
940 0 : jsonp_open_array( gui, "remove" );
941 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
942 0 : int actually_removed = !fd_gui_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
943 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
944 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
945 :
946 0 : jsonp_open_object( gui, NULL );
947 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
948 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
949 0 : jsonp_string( gui, "identity_pubkey", identity_base58 );
950 0 : jsonp_close_object( gui );
951 0 : }
952 0 : jsonp_close_array( gui );
953 0 : jsonp_close_object( gui );
954 0 : jsonp_close_envelope( gui );
955 0 : }
956 :
957 : void
958 0 : fd_gui_printf_peers_all( fd_gui_t * gui ) {
959 0 : jsonp_open_envelope( gui, "peers", "update" );
960 0 : jsonp_open_object( gui, "value" );
961 0 : jsonp_open_array( gui, "add" );
962 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
963 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ i ].pubkey->uc );
964 0 : }
965 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
966 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ i ].pubkey->uc );
967 0 : if( FD_UNLIKELY( actually_added ) ) {
968 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ i ].pubkey->uc );
969 0 : }
970 0 : }
971 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
972 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ i ].pubkey->uc ) &&
973 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ i ].pubkey->uc );
974 0 : if( FD_UNLIKELY( actually_added ) ) {
975 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ i ].pubkey->uc );
976 0 : }
977 0 : }
978 0 : jsonp_close_array( gui );
979 0 : jsonp_close_object( gui );
980 0 : jsonp_close_envelope( gui );
981 0 : }
982 :
983 : static void
984 : fd_gui_printf_ts_tile_timers( fd_gui_t * gui,
985 : fd_gui_tile_timers_t const * prev,
986 0 : fd_gui_tile_timers_t const * cur ) {
987 0 : jsonp_open_object( gui, NULL );
988 0 : jsonp_ulong( gui, "timestamp_nanos", 0 );
989 0 : jsonp_open_array( gui, "tile_timers" );
990 0 : fd_gui_printf_tile_timers( gui, prev, cur );
991 0 : jsonp_close_array( gui );
992 0 : jsonp_close_object( gui );
993 0 : }
994 :
995 : void
996 : fd_gui_printf_slot( fd_gui_t * gui,
997 0 : ulong _slot ) {
998 0 : fd_gui_slot_t * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
999 :
1000 0 : char const * level;
1001 0 : switch( slot->level ) {
1002 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1003 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1004 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1005 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1006 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1007 0 : default: level = "unknown"; break;
1008 0 : }
1009 :
1010 0 : fd_gui_slot_t * parent_slot = gui->slots[ slot->parent_slot % FD_GUI_SLOTS_CNT ];
1011 0 : if( FD_UNLIKELY( parent_slot->slot!=slot->parent_slot ) ) parent_slot = NULL;
1012 :
1013 0 : long duration_nanos = LONG_MAX;
1014 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1015 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1016 0 : }
1017 :
1018 0 : jsonp_open_envelope( gui, "slot", "update" );
1019 0 : jsonp_open_object( gui, "value" );
1020 0 : jsonp_open_object( gui, "publish" );
1021 0 : jsonp_ulong( gui, "slot", _slot );
1022 0 : jsonp_bool( gui, "mine", slot->mine );
1023 0 : jsonp_bool( gui, "skipped", slot->skipped );
1024 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui, "duration_nanos" );
1025 0 : else jsonp_long( gui, "duration_nanos", duration_nanos );
1026 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui, "completed_time_nanos" );
1027 0 : else jsonp_long( gui, "completed_time_nanos", slot->completed_time );
1028 0 : jsonp_string( gui, "level", level );
1029 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX ) ) jsonp_null( gui, "transactions" );
1030 0 : else jsonp_ulong( gui, "transactions", slot->total_txn_cnt );
1031 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX ) ) jsonp_null( gui, "vote_transactions" );
1032 0 : else jsonp_ulong( gui, "vote_transactions", slot->vote_txn_cnt );
1033 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui, "failed_transactions" );
1034 0 : else jsonp_ulong( gui, "failed_transactions", slot->failed_txn_cnt );
1035 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui, "compute_units" );
1036 0 : else jsonp_ulong( gui, "compute_units", slot->compute_units );
1037 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui, "transaction_fee" );
1038 0 : else jsonp_ulong( gui, "transaction_fee", slot->transaction_fee );
1039 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui, "priority_fee" );
1040 0 : else jsonp_ulong( gui, "priority_fee", slot->priority_fee );
1041 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui, "tips" );
1042 0 : else jsonp_ulong( gui, "tips", slot->tips );
1043 0 : jsonp_close_object( gui );
1044 0 : jsonp_close_object( gui );
1045 0 : jsonp_close_envelope( gui );
1046 0 : }
1047 :
1048 : void
1049 : fd_gui_printf_summary_ping( fd_gui_t * gui,
1050 0 : ulong id ) {
1051 0 : jsonp_open_envelope( gui, "summary", "ping" );
1052 0 : jsonp_ulong( gui, "id", id );
1053 0 : jsonp_null( gui, "value" );
1054 0 : jsonp_close_envelope( gui );
1055 0 : }
1056 :
1057 : static void
1058 : cus_scan_init( fd_gui_slot_t const * slot,
1059 : int * has_offset,
1060 0 : uint * bank_offset ) {
1061 0 : for( ulong i=0UL; i<65UL; i++ ) {
1062 0 : has_offset[ i ] = slot->cus.has_offset[ i ];
1063 0 : bank_offset[ i ] = slot->cus.start_offset[ i ];
1064 0 : }
1065 0 : }
1066 :
1067 : static ulong
1068 : cus_scan_next( fd_gui_t const * gui,
1069 : fd_gui_slot_t const * slot,
1070 : int * has_offset,
1071 0 : uint * bank_offset ) {
1072 0 : ulong min_idx = ULONG_MAX;
1073 0 : long min_timestamp = LONG_MAX;
1074 0 : for( ulong i=0UL; i<65UL; i++ ) {
1075 0 : int in_bounds = has_offset[ i ] && ((int)(bank_offset[ i ]-slot->cus.end_offset[ i ]))<0;
1076 0 : if( FD_UNLIKELY( in_bounds ) ) {
1077 0 : long timestamp = fd_gui_cu_history_decompress_timestamp( slot->cus.reference_nanos, gui->cus.history[ bank_offset[ i ]%FD_GUI_COMPUTE_UNITS_HISTORY_SZ ] );
1078 0 : if( FD_UNLIKELY( min_idx==ULONG_MAX || timestamp<min_timestamp ) ) {
1079 0 : min_timestamp = timestamp;
1080 0 : min_idx = i;
1081 0 : }
1082 0 : }
1083 0 : }
1084 :
1085 0 : if( FD_UNLIKELY( min_idx==ULONG_MAX ) ) return ULONG_MAX;
1086 0 : ulong offset = bank_offset[ min_idx ];
1087 :
1088 0 : uint diff = (uint)(int)(slot->cus.end_offset[ min_idx ]-bank_offset[ min_idx ] );
1089 0 : for( uint i=1U; i<diff; i++) {
1090 0 : uint next_offset = bank_offset[ min_idx ] + i;
1091 0 : int is_begin = fd_gui_cu_history_decompress_type( gui->cus.history[ next_offset%FD_GUI_COMPUTE_UNITS_HISTORY_SZ ] )==0UL;
1092 0 : ulong bank_idx = fd_gui_cu_history_decompress_bank( gui->cus.history[ next_offset%FD_GUI_COMPUTE_UNITS_HISTORY_SZ ] );
1093 :
1094 0 : if( FD_LIKELY( is_begin && min_idx==64UL ) ) {
1095 0 : bank_offset[ min_idx ] = next_offset;
1096 0 : return offset;
1097 0 : }
1098 0 : else if( FD_LIKELY( !is_begin && bank_idx==min_idx ) ) {
1099 0 : bank_offset[ min_idx ] = next_offset;
1100 0 : return offset;
1101 0 : }
1102 0 : }
1103 :
1104 0 : bank_offset[ min_idx ] = UINT_MAX;
1105 0 : has_offset[ min_idx ] = 0;
1106 0 : return offset;
1107 0 : }
1108 :
1109 : void
1110 : fd_gui_printf_slot_request( fd_gui_t * gui,
1111 : ulong _slot,
1112 0 : ulong id ) {
1113 0 : fd_gui_slot_t * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
1114 :
1115 0 : char const * level;
1116 0 : switch( slot->level ) {
1117 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1118 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1119 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1120 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1121 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1122 0 : default: level = "unknown"; break;
1123 0 : }
1124 :
1125 0 : fd_gui_slot_t * parent_slot = gui->slots[ slot->parent_slot % FD_GUI_SLOTS_CNT ];
1126 0 : if( FD_UNLIKELY( parent_slot->slot!=slot->parent_slot ) ) parent_slot = NULL;
1127 :
1128 0 : long duration_nanos = LONG_MAX;
1129 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1130 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1131 0 : }
1132 :
1133 0 : jsonp_open_envelope( gui, "slot", "query" );
1134 0 : jsonp_ulong( gui, "id", id );
1135 0 : jsonp_open_object( gui, "value" );
1136 :
1137 0 : jsonp_open_object( gui, "publish" );
1138 0 : jsonp_ulong( gui, "slot", _slot );
1139 0 : jsonp_bool( gui, "mine", slot->mine );
1140 0 : jsonp_bool( gui, "skipped", slot->skipped );
1141 0 : jsonp_string( gui, "level", level );
1142 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui, "duration_nanos" );
1143 0 : else jsonp_long( gui, "duration_nanos", duration_nanos );
1144 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui, "completed_time_nanos" );
1145 0 : else jsonp_long( gui, "completed_time_nanos", slot->completed_time );
1146 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX ) ) jsonp_null( gui, "transactions" );
1147 0 : else jsonp_ulong( gui, "transactions", slot->total_txn_cnt );
1148 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX ) ) jsonp_null( gui, "vote_transactions" );
1149 0 : else jsonp_ulong( gui, "vote_transactions", slot->vote_txn_cnt );
1150 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui, "failed_transactions" );
1151 0 : else jsonp_ulong( gui, "failed_transactions", slot->failed_txn_cnt );
1152 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui, "compute_units" );
1153 0 : else jsonp_ulong( gui, "compute_units", slot->compute_units );
1154 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui, "transaction_fee" );
1155 0 : else jsonp_ulong( gui, "transaction_fee", slot->transaction_fee );
1156 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui, "priority_fee" );
1157 0 : else jsonp_ulong( gui, "priority_fee", slot->priority_fee );
1158 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui, "tips" );
1159 0 : else jsonp_ulong( gui, "tips", slot->tips );
1160 0 : jsonp_close_object( gui );
1161 :
1162 0 : jsonp_close_object( gui );
1163 0 : jsonp_close_envelope( gui );
1164 0 : }
1165 :
1166 : void
1167 : fd_gui_printf_slot_request_detailed( fd_gui_t * gui,
1168 : ulong _slot,
1169 0 : ulong id ) {
1170 0 : fd_gui_slot_t * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
1171 :
1172 0 : char const * level;
1173 0 : switch( slot->level ) {
1174 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1175 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1176 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1177 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1178 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1179 0 : default: level = "unknown"; break;
1180 0 : }
1181 :
1182 0 : fd_gui_slot_t * parent_slot = gui->slots[ slot->parent_slot % FD_GUI_SLOTS_CNT ];
1183 0 : if( FD_UNLIKELY( parent_slot->slot!=slot->parent_slot ) ) parent_slot = NULL;
1184 :
1185 0 : long duration_nanos = LONG_MAX;
1186 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1187 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1188 0 : }
1189 :
1190 0 : jsonp_open_envelope( gui, "slot", "query" );
1191 0 : jsonp_ulong( gui, "id", id );
1192 0 : jsonp_open_object( gui, "value" );
1193 :
1194 0 : jsonp_open_object( gui, "publish" );
1195 0 : jsonp_ulong( gui, "slot", _slot );
1196 0 : jsonp_bool( gui, "mine", slot->mine );
1197 0 : jsonp_bool( gui, "skipped", slot->skipped );
1198 0 : jsonp_string( gui, "level", level );
1199 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui, "duration_nanos" );
1200 0 : else jsonp_long( gui, "duration_nanos", duration_nanos );
1201 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui, "completed_time_nanos" );
1202 0 : else jsonp_long( gui, "completed_time_nanos", slot->completed_time );
1203 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX ) ) jsonp_null( gui, "transactions" );
1204 0 : else jsonp_ulong( gui, "transactions", slot->total_txn_cnt );
1205 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX ) ) jsonp_null( gui, "vote_transactions" );
1206 0 : else jsonp_ulong( gui, "vote_transactions", slot->vote_txn_cnt );
1207 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui, "failed_transactions" );
1208 0 : else jsonp_ulong( gui, "failed_transactions", slot->failed_txn_cnt );
1209 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui, "compute_units" );
1210 0 : else jsonp_ulong( gui, "compute_units", slot->compute_units );
1211 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui, "transaction_fee" );
1212 0 : else jsonp_ulong( gui, "transaction_fee", slot->transaction_fee );
1213 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui, "priority_fee" );
1214 0 : else jsonp_ulong( gui, "priority_fee", slot->priority_fee );
1215 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui, "tips" );
1216 0 : else jsonp_ulong( gui, "tips", slot->tips );
1217 0 : jsonp_close_object( gui );
1218 :
1219 0 : if( FD_LIKELY( slot->leader_state==FD_GUI_SLOT_LEADER_ENDED ) ) {
1220 0 : fd_gui_printf_waterfall( gui, slot->waterfall_begin, slot->waterfall_end );
1221 :
1222 0 : if( FD_LIKELY( gui->summary.tile_timers_leader_history_slot[ slot->tile_timers_history_idx ]==_slot ) ) {
1223 0 : jsonp_open_array( gui, "tile_timers" );
1224 0 : fd_gui_tile_timers_t const * prev_timer = gui->summary.tile_timers_leader_history[ slot->tile_timers_history_idx ][ 0 ];
1225 0 : for( ulong i=1UL; i<gui->summary.tile_timers_leader_history_slot_sample_cnt[ slot->tile_timers_history_idx ]; i++ ) {
1226 0 : fd_gui_tile_timers_t const * cur_timer = gui->summary.tile_timers_leader_history[ slot->tile_timers_history_idx ][ i ];
1227 0 : fd_gui_printf_ts_tile_timers( gui, prev_timer, cur_timer );
1228 0 : prev_timer = cur_timer;
1229 0 : }
1230 0 : jsonp_close_array( gui );
1231 0 : } else {
1232 : /* Our tile timers were overwritten. */
1233 0 : jsonp_null( gui, "tile_timers" );
1234 0 : }
1235 :
1236 0 : fd_gui_printf_tile_stats( gui, slot->tile_stats_begin, slot->tile_stats_end );
1237 0 : } else {
1238 0 : jsonp_null( gui, "waterfall" );
1239 0 : jsonp_null( gui, "tile_timers" );
1240 0 : jsonp_null( gui, "tile_primary_metric" );
1241 0 : }
1242 :
1243 0 : int overwritten = 0;
1244 0 : for( ulong i=0UL; i<65UL; i++) {
1245 0 : if( FD_UNLIKELY( slot->cus.has_offset[ i ] && slot->cus.start_offset[ i ]+FD_GUI_COMPUTE_UNITS_HISTORY_SZ<gui->cus.offset ) ) {
1246 0 : overwritten = 1;
1247 0 : break;
1248 0 : }
1249 0 : }
1250 :
1251 0 : int processed_all_microblocks = slot->cus.microblocks_upper_bound!=USHORT_MAX && (slot->cus.begin_microblocks==slot->cus.end_microblocks) && (slot->cus.begin_microblocks==slot->cus.microblocks_upper_bound);
1252 0 : if( FD_LIKELY( !overwritten && processed_all_microblocks ) ) {
1253 0 : jsonp_open_object( gui, "compute_units" );
1254 0 : jsonp_ulong( gui, "max_compute_units", slot->cus.max_compute_units );
1255 0 : jsonp_long( gui, "start_timestamp_nanos", slot->cus.leader_start_time );
1256 0 : jsonp_long( gui, "target_end_timestamp_nanos", slot->cus.leader_end_time );
1257 0 : jsonp_open_array( gui, "compute_unit_timestamps_nanos" );
1258 0 : uint bank_offset[ 65 ];
1259 0 : int has_offset[ 65 ];
1260 0 : cus_scan_init( slot, has_offset, bank_offset );
1261 :
1262 0 : ulong offset;
1263 0 : while( (offset=cus_scan_next( gui, slot, has_offset, bank_offset ))!=ULONG_MAX ) {
1264 0 : long timestamp = fd_gui_cu_history_decompress_timestamp( slot->cus.reference_nanos, gui->cus.history[ offset%FD_GUI_COMPUTE_UNITS_HISTORY_SZ ] );
1265 0 : jsonp_long( gui, NULL, timestamp );
1266 0 : }
1267 0 : jsonp_close_array( gui );
1268 0 : jsonp_open_array( gui, "compute_units_deltas" );
1269 0 : cus_scan_init( slot, has_offset, bank_offset );
1270 :
1271 0 : while( (offset=cus_scan_next( gui, slot, has_offset, bank_offset ))!=ULONG_MAX ) {
1272 0 : int is_begin = fd_gui_cu_history_decompress_type( gui->cus.history[ offset%FD_GUI_COMPUTE_UNITS_HISTORY_SZ ] )==FD_GUI_EXECUTION_TYPE_BEGIN;
1273 0 : ulong compute_units = fd_gui_cu_history_decompress_compute_units( gui->cus.history[ offset%FD_GUI_COMPUTE_UNITS_HISTORY_SZ ] );
1274 :
1275 0 : if( FD_LIKELY( is_begin ) ) {
1276 0 : jsonp_ulong( gui, NULL, compute_units );
1277 0 : } else {
1278 0 : jsonp_long( gui, NULL, -(long)compute_units );
1279 0 : }
1280 0 : }
1281 0 : jsonp_close_array( gui );
1282 0 : jsonp_open_array( gui, "active_bank_count" );
1283 0 : cus_scan_init( slot, has_offset, bank_offset );
1284 :
1285 0 : ulong active_bank_cnt = 0UL;
1286 0 : ulong bank_active_cnt[ 64 ] = {0UL};
1287 0 : while( (offset=cus_scan_next( gui, slot, has_offset, bank_offset ))!=ULONG_MAX ) {
1288 0 : int is_begin = fd_gui_cu_history_decompress_type( gui->cus.history[ offset%FD_GUI_COMPUTE_UNITS_HISTORY_SZ ] )==FD_GUI_EXECUTION_TYPE_BEGIN;
1289 0 : int active_bank_change = fd_gui_cu_history_decompress_active_bank_change( gui->cus.history[ offset%FD_GUI_COMPUTE_UNITS_HISTORY_SZ ] );
1290 0 : ulong bank_idx = fd_gui_cu_history_decompress_bank( gui->cus.history[ offset%FD_GUI_COMPUTE_UNITS_HISTORY_SZ ] );
1291 :
1292 0 : if( FD_LIKELY( active_bank_change ) ) {
1293 0 : if( FD_LIKELY( is_begin ) ) {
1294 0 : if( FD_LIKELY( !bank_active_cnt[ bank_idx ] ) ) active_bank_cnt++;
1295 0 : bank_active_cnt[ bank_idx ]++;
1296 0 : } else {
1297 0 : if( FD_LIKELY( bank_active_cnt[ bank_idx ]==1UL ) ) active_bank_cnt--;
1298 0 : bank_active_cnt[ bank_idx ]--;
1299 0 : }
1300 0 : }
1301 :
1302 0 : jsonp_ulong( gui, NULL, active_bank_cnt );
1303 0 : }
1304 0 : jsonp_close_array( gui );
1305 0 : jsonp_close_object( gui );
1306 0 : } else {
1307 0 : jsonp_null( gui, "compute_units" );
1308 0 : }
1309 :
1310 0 : jsonp_close_object( gui );
1311 0 : jsonp_close_envelope( gui );
1312 0 : }
1313 :
1314 : #endif /* HEADER_fd_src_disco_gui_fd_gui_printf_h */
|