Line data Source code
1 : #include "fd_guih_printf.h"
2 :
3 : #include "../../disco/bundle/fd_bundle_tile.h"
4 : #include "../../disco/diag/fd_diag_tile.h"
5 : #include "../../waltz/http/fd_http_server_private.h"
6 : #include "../../ballet/utf8/fd_utf8.h"
7 : #include "../../disco/fd_txn_m.h"
8 : #include "../../disco/metrics/fd_metrics.h"
9 : #include "../../disco/topo/fd_topob.h"
10 : #include "../../util/fd_version.h"
11 :
12 : static void
13 0 : jsonp_strip_trailing_comma( fd_http_server_t * http ) {
14 0 : if( FD_LIKELY( !http->stage_err &&
15 0 : http->stage_len>=1UL &&
16 0 : http->oring[ (http->stage_off%http->oring_sz)+http->stage_len-1UL ]==(uchar)',' ) ) {
17 0 : http->stage_len--;
18 0 : }
19 0 : }
20 :
21 : static void
22 : jsonp_open_object( fd_http_server_t * http,
23 0 : char const * key ) {
24 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":{", key );
25 0 : else fd_http_server_printf( http, "{" );
26 0 : }
27 :
28 : static void
29 0 : jsonp_close_object( fd_http_server_t * http ) {
30 0 : jsonp_strip_trailing_comma( http );
31 0 : fd_http_server_printf( http, "}," );
32 0 : }
33 :
34 : static void
35 : jsonp_open_array( fd_http_server_t * http,
36 0 : char const * key ) {
37 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":[", key );
38 0 : else fd_http_server_printf( http, "[" );
39 0 : }
40 :
41 : static void
42 0 : jsonp_close_array( fd_http_server_t * http ) {
43 0 : jsonp_strip_trailing_comma( http );
44 0 : fd_http_server_printf( http, "]," );
45 0 : }
46 :
47 : static void
48 : jsonp_ulong( fd_http_server_t * http,
49 : char const * key,
50 0 : ulong value ) {
51 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%lu,", key, value );
52 0 : else fd_http_server_printf( http, "%lu,", value );
53 0 : }
54 :
55 : static void
56 : jsonp_long( fd_http_server_t * http,
57 : char const * key,
58 0 : long value ) {
59 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%ld,", key, value );
60 0 : else fd_http_server_printf( http, "%ld,", value );
61 0 : }
62 :
63 : static void
64 : jsonp_double( fd_http_server_t * http,
65 : char const * key,
66 0 : double value ) {
67 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%.2f,", key, value );
68 0 : else fd_http_server_printf( http, "%.2f,", value );
69 0 : }
70 :
71 : static void
72 : jsonp_ulong_as_str( fd_http_server_t * http,
73 : char const * key,
74 0 : ulong value ) {
75 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":\"%lu\",", key, value );
76 0 : else fd_http_server_printf( http, "\"%lu\",", value );
77 0 : }
78 :
79 : static void
80 : jsonp_long_as_str( fd_http_server_t * http,
81 : char const * key,
82 0 : long value ) {
83 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":\"%ld\",", key, value );
84 0 : else fd_http_server_printf( http, "\"%ld\",", value );
85 0 : }
86 :
87 : static void
88 : jsonp_sanitize_str( fd_http_server_t * http,
89 0 : ulong start_len ) {
90 : /* escape quotemark, reverse solidus, and control chars U+0000 through U+001F
91 : just replace with a space */
92 0 : uchar * data = http->oring;
93 0 : for( ulong i=start_len; i<http->stage_len; i++ ) {
94 0 : if( FD_UNLIKELY( data[ (http->stage_off%http->oring_sz)+i ] < 0x20 ||
95 0 : data[ (http->stage_off%http->oring_sz)+i ] == '"' ||
96 0 : data[ (http->stage_off%http->oring_sz)+i ] == '\\' ) ) {
97 0 : data[ (http->stage_off%http->oring_sz)+i ] = ' ';
98 0 : }
99 0 : }
100 0 : }
101 :
102 : static void
103 : jsonp_string( fd_http_server_t * http,
104 : char const * key,
105 0 : char const * value ) {
106 0 : char * val = (void *)value;
107 0 : if( FD_LIKELY( value ) ) {
108 0 : if( FD_UNLIKELY( !fd_utf8_verify( value, strlen( value ) ) )) {
109 0 : val = NULL;
110 0 : }
111 0 : }
112 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":", key );
113 0 : if( FD_LIKELY( val ) ) {
114 0 : fd_http_server_printf( http, "\"" );
115 0 : ulong start_len = http->stage_len;
116 0 : fd_http_server_printf( http, "%s", val );
117 0 : jsonp_sanitize_str( http, start_len );
118 0 : fd_http_server_printf( http, "\"," );
119 0 : } else {
120 0 : fd_http_server_printf( http, "null," );
121 0 : }
122 0 : }
123 :
124 : static void
125 : jsonp_bool( fd_http_server_t * http,
126 : char const * key,
127 0 : int value ) {
128 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%s,", key, value ? "true" : "false" );
129 0 : else fd_http_server_printf( http, "%s,", value ? "true" : "false" );
130 0 : }
131 :
132 : static void
133 : jsonp_null( fd_http_server_t * http,
134 0 : char const * key ) {
135 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\": null,", key );
136 0 : else fd_http_server_printf( http, "null," );
137 0 : }
138 :
139 : static void
140 : jsonp_open_envelope( fd_http_server_t * http,
141 : char const * topic,
142 0 : char const * key ) {
143 0 : jsonp_open_object( http, NULL );
144 0 : jsonp_string( http, "topic", topic );
145 0 : jsonp_string( http, "key", key );
146 0 : }
147 :
148 : static void
149 0 : jsonp_close_envelope( fd_http_server_t * http ) {
150 0 : jsonp_close_object( http );
151 0 : jsonp_strip_trailing_comma( http );
152 0 : }
153 :
154 : void
155 : fd_guih_printf_open_query_response_envelope( fd_http_server_t * http,
156 : char const * topic,
157 : char const * key,
158 0 : ulong id ) {
159 0 : jsonp_open_object( http, NULL );
160 0 : jsonp_string( http, "topic", topic );
161 0 : jsonp_string( http, "key", key );
162 0 : jsonp_ulong( http, "id", id );
163 0 : }
164 :
165 : void
166 0 : fd_guih_printf_close_query_response_envelope( fd_http_server_t * http ) {
167 0 : jsonp_close_object( http );
168 0 : jsonp_strip_trailing_comma( http );
169 0 : }
170 :
171 : void
172 : fd_guih_printf_null_query_response( fd_http_server_t * http,
173 : char const * topic,
174 : char const * key,
175 0 : ulong id ) {
176 0 : fd_guih_printf_open_query_response_envelope( http, topic, key, id );
177 0 : jsonp_null( http, "value" );
178 0 : fd_guih_printf_close_query_response_envelope( http );
179 0 : }
180 :
181 : void
182 0 : fd_guih_printf_version( fd_guih_t * gui ) {
183 0 : jsonp_open_envelope( gui->http, "summary", "version" );
184 0 : jsonp_string( gui->http, "value", gui->summary.version );
185 0 : jsonp_close_envelope( gui->http );
186 0 : }
187 :
188 : void
189 0 : fd_guih_printf_cluster( fd_guih_t * gui ) {
190 0 : jsonp_open_envelope( gui->http, "summary", "cluster" );
191 0 : jsonp_string( gui->http, "value", gui->summary.cluster );
192 0 : jsonp_close_envelope( gui->http );
193 0 : }
194 :
195 : void
196 0 : fd_guih_printf_commit_hash( fd_guih_t * gui ) {
197 0 : jsonp_open_envelope( gui->http, "summary", "commit_hash" );
198 0 : jsonp_string( gui->http, "value", fd_commit_ref_cstr );
199 0 : jsonp_close_envelope( gui->http );
200 0 : }
201 :
202 : void
203 0 : fd_guih_printf_identity_key( fd_guih_t * gui ) {
204 0 : jsonp_open_envelope( gui->http, "summary", "identity_key" );
205 0 : jsonp_string( gui->http, "value", gui->summary.identity_key_base58 );
206 0 : jsonp_close_envelope( gui->http );
207 0 : }
208 :
209 : void
210 0 : fd_guih_printf_vote_key( fd_guih_t * gui ) {
211 0 : jsonp_open_envelope( gui->http, "summary", "vote_key" );
212 0 : if( FD_LIKELY( gui->summary.has_vote_key ) ) jsonp_string( gui->http, "value", gui->summary.vote_key_base58 );
213 0 : else jsonp_null( gui->http, "value" );
214 0 : jsonp_close_envelope( gui->http );
215 0 : }
216 :
217 : void
218 0 : fd_guih_printf_startup_time_nanos( fd_guih_t * gui ) {
219 0 : jsonp_open_envelope( gui->http, "summary", "startup_time_nanos" );
220 0 : jsonp_long_as_str( gui->http, "value", gui->summary.startup_time_nanos );
221 0 : jsonp_close_envelope( gui->http );
222 0 : }
223 :
224 : void
225 0 : fd_guih_printf_server_time_nanos( fd_guih_t * gui, long now ) {
226 0 : jsonp_open_envelope( gui->http, "summary", "server_time_nanos" );
227 0 : jsonp_long_as_str( gui->http, "value", now );
228 0 : jsonp_close_envelope( gui->http );
229 0 : }
230 :
231 : void
232 0 : fd_guih_printf_vote_distance( fd_guih_t * gui ) {
233 0 : jsonp_open_envelope( gui->http, "summary", "vote_distance" );
234 0 : jsonp_ulong( gui->http, "value", gui->summary.vote_distance );
235 0 : jsonp_close_envelope( gui->http );
236 0 : }
237 :
238 : void
239 0 : fd_guih_printf_repair_slot( fd_guih_t * gui ) {
240 0 : jsonp_open_envelope( gui->http, "summary", "repair_slot" );
241 0 : if( FD_LIKELY( gui->summary.slot_repair!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_repair );
242 0 : else jsonp_null ( gui->http, "value" );
243 0 : jsonp_close_envelope( gui->http );
244 0 : }
245 :
246 : void
247 0 : fd_guih_printf_turbine_slot( fd_guih_t * gui ) {
248 0 : jsonp_open_envelope( gui->http, "summary", "turbine_slot" );
249 0 : if( FD_LIKELY( gui->summary.slot_turbine!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_turbine );
250 0 : else jsonp_null ( gui->http, "value" );
251 0 : jsonp_close_envelope( gui->http );
252 0 : }
253 :
254 : void
255 0 : fd_guih_printf_reset_slot( fd_guih_t * gui ) {
256 0 : jsonp_open_envelope( gui->http, "summary", "reset_slot" );
257 0 : if( FD_LIKELY( gui->summary.slot_reset!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_reset );
258 0 : else jsonp_null ( gui->http, "value" );
259 0 : jsonp_close_envelope( gui->http );
260 0 : }
261 :
262 : void
263 0 : fd_guih_printf_storage_slot( fd_guih_t * gui ) {
264 0 : jsonp_open_envelope( gui->http, "summary", "storage_slot" );
265 0 : if( FD_LIKELY( gui->summary.slot_storage!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_storage );
266 0 : else jsonp_null ( gui->http, "value" );
267 0 : jsonp_close_envelope( gui->http );
268 0 : }
269 :
270 : void
271 0 : fd_guih_printf_active_fork_cnt( fd_guih_t * gui ) {
272 0 : jsonp_open_envelope( gui->http, "summary", "active_fork_count" );
273 0 : if( FD_LIKELY( gui->summary.active_fork_cnt!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.active_fork_cnt );
274 0 : else jsonp_null ( gui->http, "value" );
275 0 : jsonp_close_envelope( gui->http );
276 0 : }
277 :
278 : void
279 0 : fd_guih_printf_slot_caught_up( fd_guih_t * gui ) {
280 0 : jsonp_open_envelope( gui->http, "summary", "slot_caught_up" );
281 0 : if( FD_LIKELY( gui->summary.slot_caught_up!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_caught_up );
282 0 : else jsonp_null ( gui->http, "value" );
283 0 : jsonp_close_envelope( gui->http );
284 0 : }
285 :
286 : void
287 0 : fd_guih_printf_catch_up_history( fd_guih_t * gui ) {
288 0 : jsonp_open_envelope( gui->http, "summary", "catch_up_history" );
289 0 : jsonp_open_object( gui->http, "value" );
290 0 : jsonp_open_array( gui->http, "turbine" );
291 0 : for( ulong i=0UL; i<gui->summary.catch_up_turbine_sz; i+=2 ) {
292 0 : for( ulong j=gui->summary.catch_up_turbine[ i ]; j<=gui->summary.catch_up_turbine[ i+1UL ]; j++ ) {
293 0 : jsonp_ulong( gui->http, NULL, j );
294 0 : }
295 0 : }
296 0 : jsonp_close_array( gui->http );
297 0 : jsonp_open_array( gui->http, "repair" );
298 0 : for( ulong i=0UL; i<gui->summary.catch_up_repair_sz; i+=2 ) {
299 0 : for( ulong j=gui->summary.catch_up_repair[ i ]; j<=gui->summary.catch_up_repair[ i+1UL ]; j++ ) {
300 0 : jsonp_ulong( gui->http, NULL, j );
301 0 : }
302 0 : }
303 0 : jsonp_close_array( gui->http );
304 :
305 0 : if( FD_LIKELY( gui->summary.boot_progress.phase==FD_GUIH_BOOT_PROGRESS_TYPE_CATCHING_UP ) ) {
306 0 : ulong min_slot = ULONG_MAX;
307 0 : long min_ts = LONG_MAX;
308 :
309 0 : #define SHREDS_REV_ITER( age_ns, code_staged, code_archive ) \
310 0 : do { \
311 0 : if( FD_UNLIKELY( gui->summary.boot_progress.catching_up_time_nanos==0L ) ) break; \
312 0 : for( ulong i=gui->shreds.staged_tail; i>gui->shreds.staged_head; i-- ) { \
313 0 : fd_guih_slot_staged_shred_event_t * event = &gui->shreds.staged[ (i-1UL) % FD_GUIH_SHREDS_STAGING_SZ ]; \
314 0 : if( FD_UNLIKELY( event->timestamp < gui->summary.boot_progress.catching_up_time_nanos - age_ns ) ) break; \
315 0 : do { code_staged } while(0); \
316 0 : } \
317 0 : fd_guih_slot_t * s = fd_guih_get_slot( gui, gui->shreds.history_slot ); \
318 0 : while( s \
319 0 : && s->shreds.start_offset!=ULONG_MAX \
320 0 : && s->shreds.end_offset!=ULONG_MAX \
321 0 : && s->shreds.end_offset>s->shreds.start_offset \
322 0 : && gui->shreds.history[ (s->shreds.end_offset-1UL) % FD_GUIH_SHREDS_HISTORY_SZ ].timestamp + age_ns > gui->summary.boot_progress.catching_up_time_nanos ) { \
323 0 : for( ulong i=s->shreds.end_offset; i>s->shreds.start_offset; i-- ) { \
324 0 : fd_guih_slot_history_shred_event_t * event = &gui->shreds.history[ (i-1UL) % FD_GUIH_SHREDS_HISTORY_SZ ]; (void)event; \
325 0 : do { code_archive } while (0); \
326 0 : } \
327 0 : s = fd_guih_get_slot( gui, s->parent_slot ); \
328 0 : } \
329 0 : } while(0);
330 :
331 0 : SHREDS_REV_ITER(
332 0 : 15000000000,
333 0 : {
334 0 : min_slot = fd_ulong_min( min_slot, event->slot );
335 0 : min_ts = fd_long_min( min_ts, event->timestamp );
336 0 : },
337 0 : {
338 0 : min_slot = fd_ulong_min( min_slot, s->slot );
339 0 : min_ts = fd_long_min( min_ts, event->timestamp );
340 0 : }
341 0 : )
342 :
343 0 : jsonp_open_object( gui->http, "shreds" );
344 0 : jsonp_ulong ( gui->http, "reference_slot", min_slot );
345 0 : jsonp_long_as_str( gui->http, "reference_ts", min_ts );
346 :
347 0 : jsonp_open_array( gui->http, "slot_delta" );
348 0 : SHREDS_REV_ITER(
349 0 : 15000000000L,
350 0 : { jsonp_ulong( gui->http, NULL, event->slot-min_slot ); },
351 0 : { jsonp_ulong( gui->http, NULL, s->slot-min_slot ); }
352 0 : )
353 0 : jsonp_close_array( gui->http );
354 0 : jsonp_open_array( gui->http, "shred_idx" );
355 0 : SHREDS_REV_ITER(
356 0 : 15000000000L,
357 0 : {
358 0 : if( FD_LIKELY( event->shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, event->shred_idx );
359 0 : else jsonp_null ( gui->http, NULL );
360 0 : },
361 0 : {
362 0 : if( FD_LIKELY( event->shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, event->shred_idx );
363 0 : else jsonp_null ( gui->http, NULL );
364 0 : }
365 0 : )
366 0 : jsonp_close_array( gui->http );
367 0 : jsonp_open_array( gui->http, "event" );
368 0 : SHREDS_REV_ITER(
369 0 : 15000000000L,
370 0 : { jsonp_ulong( gui->http, NULL, event->event ); },
371 0 : { jsonp_ulong( gui->http, NULL, event->event ); }
372 0 : )
373 0 : jsonp_close_array( gui->http );
374 0 : jsonp_open_array( gui->http, "event_ts_delta" );
375 0 : SHREDS_REV_ITER(
376 0 : 15000000000L,
377 0 : { jsonp_long_as_str( gui->http, NULL, event->timestamp-min_ts ); },
378 0 : { jsonp_long_as_str( gui->http, NULL, event->timestamp-min_ts ); }
379 0 : )
380 0 : jsonp_close_array( gui->http );
381 0 : jsonp_close_object( gui->http );
382 0 : } else {
383 0 : jsonp_null( gui->http, "shreds" );
384 0 : }
385 :
386 0 : jsonp_close_object( gui->http );
387 0 : jsonp_close_envelope( gui->http );
388 0 : }
389 :
390 : void
391 0 : fd_guih_printf_vote_state( fd_guih_t * gui ) {
392 0 : jsonp_open_envelope( gui->http, "summary", "vote_state" );
393 0 : switch( gui->summary.vote_state ) {
394 0 : case FD_GUIH_VOTE_STATE_NON_VOTING:
395 0 : jsonp_string( gui->http, "value", "non-voting" );
396 0 : break;
397 0 : case FD_GUIH_VOTE_STATE_VOTING:
398 0 : jsonp_string( gui->http, "value", "voting" );
399 0 : break;
400 0 : case FD_GUIH_VOTE_STATE_DELINQUENT:
401 0 : jsonp_string( gui->http, "value", "delinquent" );
402 0 : break;
403 0 : default:
404 0 : FD_LOG_ERR(( "unknown vote state %d", gui->summary.vote_state ));
405 0 : }
406 0 : jsonp_close_envelope( gui->http );
407 0 : }
408 :
409 : void
410 0 : fd_guih_printf_skipped_history( fd_guih_t * gui, ulong epoch_idx ) {
411 0 : jsonp_open_envelope( gui->http, "slot", "skipped_history" );
412 0 : jsonp_open_array( gui->http, "value" );
413 0 : ulong start_slot = gui->epoch.epochs[ epoch_idx ].start_slot;
414 0 : ulong end_slot = gui->epoch.epochs[ epoch_idx ].end_slot;
415 0 : for( ulong s=start_slot; s<fd_ulong_min( end_slot, start_slot+FD_GUIH_SLOTS_CNT ); s++ ) {
416 0 : if( FD_LIKELY( gui->summary.slot_completed==ULONG_MAX ) ) break;
417 0 : fd_guih_slot_t * slot = fd_guih_get_slot( gui, s );
418 :
419 0 : if( FD_UNLIKELY( !slot ) ) continue;
420 0 : if( FD_UNLIKELY( slot->mine && slot->skipped ) ) jsonp_ulong( gui->http, NULL, slot->slot );
421 0 : }
422 0 : jsonp_close_array( gui->http );
423 0 : jsonp_close_envelope( gui->http );
424 0 : }
425 :
426 : void
427 0 : fd_guih_printf_skipped_history_cluster( fd_guih_t * gui, ulong epoch_idx ) {
428 0 : jsonp_open_envelope( gui->http, "slot", "skipped_history_cluster" );
429 0 : jsonp_open_array( gui->http, "value" );
430 0 : ulong start_slot = gui->epoch.epochs[ epoch_idx ].start_slot;
431 0 : ulong end_slot = gui->epoch.epochs[ epoch_idx ].end_slot;
432 0 : for( ulong s=start_slot; s<fd_ulong_min( end_slot, start_slot+FD_GUIH_SLOTS_CNT ); s++ ) {
433 0 : if( FD_LIKELY( gui->summary.slot_completed==ULONG_MAX ) ) break;
434 0 : fd_guih_slot_t * slot = fd_guih_get_slot( gui, s );
435 :
436 0 : if( FD_UNLIKELY( !slot ) ) continue;
437 0 : if( FD_UNLIKELY( slot->skipped ) ) jsonp_ulong( gui->http, NULL, slot->slot );
438 0 : }
439 0 : jsonp_close_array( gui->http );
440 0 : jsonp_close_envelope( gui->http );
441 0 : }
442 :
443 : /* TODO: deprecated */
444 : void
445 0 : fd_guih_printf_vote_latency_history( fd_guih_t * gui ) {
446 0 : jsonp_open_envelope( gui->http, "slot", "vote_latency_history" );
447 0 : jsonp_open_array( gui->http, "value" );
448 0 : FD_TEST( gui->summary.late_votes_sz % 2UL == 0UL );
449 0 : for( ulong i=0UL; i<gui->summary.late_votes_sz; i++ ) jsonp_ulong( gui->http, NULL, gui->summary.late_votes[ i ] );
450 0 : jsonp_close_array( gui->http );
451 0 : jsonp_close_envelope( gui->http );
452 0 : }
453 :
454 : void
455 0 : fd_guih_printf_late_votes_history( fd_guih_t * gui ) {
456 0 : jsonp_open_envelope( gui->http, "slot", "late_votes_history" );
457 0 : jsonp_open_object( gui->http, "value" );
458 0 : jsonp_open_array( gui->http, "slot" );
459 0 : for( ulong i=0UL; i<gui->summary.late_votes_sz; i++ ) jsonp_ulong( gui->http, NULL, gui->summary.late_votes[ i ] );
460 0 : jsonp_close_array( gui->http );
461 0 : jsonp_open_array( gui->http, "latency" );
462 0 : for( long i=0UL; i<(long)gui->summary.late_votes_sz-1L; i+=2L ) {
463 0 : FD_TEST( (ulong)i+1<gui->summary.late_votes_sz );
464 0 : ulong s = gui->summary.late_votes[ i ];
465 0 : ulong s2 = gui->summary.late_votes[ i + 1 ];
466 0 : for( ulong j=s; j<=fd_ulong_min( s2, s+FD_GUIH_SLOTS_CNT ); j++ ) {
467 0 : fd_guih_slot_t * slot = fd_guih_get_slot( gui, j );
468 0 : if( FD_UNLIKELY( slot && slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, NULL, slot->vote_latency );
469 0 : else jsonp_null( gui->http, NULL );
470 0 : }
471 0 : }
472 0 : jsonp_close_array( gui->http );
473 0 : jsonp_close_object( gui->http );
474 0 : jsonp_close_envelope( gui->http );
475 0 : }
476 :
477 : void
478 0 : fd_guih_printf_tps_history( fd_guih_t * gui ) {
479 0 : jsonp_open_envelope( gui->http, "summary", "tps_history" );
480 0 : jsonp_open_array( gui->http, "value" );
481 :
482 0 : for( ulong i=0UL; i<FD_GUIH_TPS_HISTORY_SAMPLE_CNT; i++ ) {
483 0 : ulong idx = (gui->summary.estimated_tps_history_idx+i) % FD_GUIH_TPS_HISTORY_SAMPLE_CNT;
484 0 : ulong vote_cnt = gui->summary.estimated_tps_history[ idx ].vote_failed
485 0 : + gui->summary.estimated_tps_history[ idx ].vote_success;
486 0 : ulong total_cnt = vote_cnt
487 0 : + gui->summary.estimated_tps_history[ idx ].nonvote_success
488 0 : + gui->summary.estimated_tps_history[ idx ].nonvote_failed;
489 0 : jsonp_open_array( gui->http, NULL );
490 0 : jsonp_double( gui->http, NULL, (double)total_cnt/(double)FD_GUIH_TPS_HISTORY_WINDOW_DURATION_SECONDS );
491 0 : jsonp_double( gui->http, NULL, (double)vote_cnt/(double)FD_GUIH_TPS_HISTORY_WINDOW_DURATION_SECONDS );
492 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ].nonvote_success/(double)FD_GUIH_TPS_HISTORY_WINDOW_DURATION_SECONDS );
493 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ].nonvote_failed/(double)FD_GUIH_TPS_HISTORY_WINDOW_DURATION_SECONDS );
494 0 : jsonp_close_array( gui->http );
495 0 : }
496 :
497 0 : jsonp_close_array( gui->http );
498 0 : jsonp_close_envelope( gui->http );
499 0 : }
500 :
501 : void
502 0 : fd_guih_printf_startup_progress( fd_guih_t * gui ) {
503 0 : char const * phase;
504 :
505 0 : switch( gui->summary.startup_progress.phase ) {
506 0 : case FD_GUIH_START_PROGRESS_TYPE_INITIALIZING:
507 0 : phase = "initializing";
508 0 : break;
509 0 : case FD_GUIH_START_PROGRESS_TYPE_SEARCHING_FOR_FULL_SNAPSHOT:
510 0 : phase = "searching_for_full_snapshot";
511 0 : break;
512 0 : case FD_GUIH_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT:
513 0 : phase = "downloading_full_snapshot";
514 0 : break;
515 0 : case FD_GUIH_START_PROGRESS_TYPE_SEARCHING_FOR_INCREMENTAL_SNAPSHOT:
516 0 : phase = "searching_for_incremental_snapshot";
517 0 : break;
518 0 : case FD_GUIH_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT:
519 0 : phase = "downloading_incremental_snapshot";
520 0 : break;
521 0 : case FD_GUIH_START_PROGRESS_TYPE_CLEANING_BLOCK_STORE:
522 0 : phase = "cleaning_blockstore";
523 0 : break;
524 0 : case FD_GUIH_START_PROGRESS_TYPE_CLEANING_ACCOUNTS:
525 0 : phase = "cleaning_accounts";
526 0 : break;
527 0 : case FD_GUIH_START_PROGRESS_TYPE_LOADING_LEDGER:
528 0 : phase = "loading_ledger";
529 0 : break;
530 0 : case FD_GUIH_START_PROGRESS_TYPE_PROCESSING_LEDGER:
531 0 : phase = "processing_ledger";
532 0 : break;
533 0 : case FD_GUIH_START_PROGRESS_TYPE_STARTING_SERVICES:
534 0 : phase = "starting_services";
535 0 : break;
536 0 : case FD_GUIH_START_PROGRESS_TYPE_HALTED:
537 0 : phase = "halted";
538 0 : break;
539 0 : case FD_GUIH_START_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY:
540 0 : phase = "waiting_for_supermajority";
541 0 : break;
542 0 : case FD_GUIH_START_PROGRESS_TYPE_RUNNING:
543 0 : phase = "running";
544 0 : break;
545 0 : default:
546 0 : FD_LOG_ERR(( "unknown phase %d", gui->summary.startup_progress.phase ));
547 0 : }
548 :
549 0 : jsonp_open_envelope( gui->http, "summary", "startup_progress" );
550 0 : jsonp_open_object( gui->http, "value" );
551 0 : jsonp_string( gui->http, "phase", phase );
552 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUIH_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT) ) {
553 0 : char peer_addr[ 64 ];
554 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_progress.startup_full_snapshot_peer_ip_addr), gui->summary.startup_progress.startup_full_snapshot_peer_port ) );
555 :
556 0 : jsonp_string( gui->http, "downloading_full_snapshot_peer", peer_addr );
557 0 : jsonp_ulong( gui->http, "downloading_full_snapshot_slot", gui->summary.startup_progress.startup_full_snapshot_slot );
558 0 : jsonp_double( gui->http, "downloading_full_snapshot_elapsed_secs", gui->summary.startup_progress.startup_full_snapshot_elapsed_secs );
559 0 : jsonp_double( gui->http, "downloading_full_snapshot_remaining_secs", gui->summary.startup_progress.startup_full_snapshot_remaining_secs );
560 0 : jsonp_double( gui->http, "downloading_full_snapshot_throughput", gui->summary.startup_progress.startup_full_snapshot_throughput );
561 0 : jsonp_ulong( gui->http, "downloading_full_snapshot_total_bytes", gui->summary.startup_progress.startup_full_snapshot_total_bytes );
562 0 : jsonp_ulong( gui->http, "downloading_full_snapshot_current_bytes", gui->summary.startup_progress.startup_full_snapshot_current_bytes );
563 0 : } else {
564 0 : jsonp_null( gui->http, "downloading_full_snapshot_peer" );
565 0 : jsonp_null( gui->http, "downloading_full_snapshot_slot" );
566 0 : jsonp_null( gui->http, "downloading_full_snapshot_elapsed_secs" );
567 0 : jsonp_null( gui->http, "downloading_full_snapshot_remaining_secs" );
568 0 : jsonp_null( gui->http, "downloading_full_snapshot_throughput" );
569 0 : jsonp_null( gui->http, "downloading_full_snapshot_total_bytes" );
570 0 : jsonp_null( gui->http, "downloading_full_snapshot_current_bytes" );
571 0 : }
572 :
573 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUIH_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT) ) {
574 0 : char peer_addr[ 64 ];
575 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_progress.startup_incremental_snapshot_peer_ip_addr), gui->summary.startup_progress.startup_incremental_snapshot_peer_port ) );
576 :
577 0 : jsonp_string( gui->http, "downloading_incremental_snapshot_peer", peer_addr );
578 0 : jsonp_ulong( gui->http, "downloading_incremental_snapshot_slot", gui->summary.startup_progress.startup_incremental_snapshot_slot );
579 0 : jsonp_double( gui->http, "downloading_incremental_snapshot_elapsed_secs", gui->summary.startup_progress.startup_incremental_snapshot_elapsed_secs );
580 0 : jsonp_double( gui->http, "downloading_incremental_snapshot_remaining_secs", gui->summary.startup_progress.startup_incremental_snapshot_remaining_secs );
581 0 : jsonp_double( gui->http, "downloading_incremental_snapshot_throughput", gui->summary.startup_progress.startup_incremental_snapshot_throughput );
582 0 : jsonp_ulong( gui->http, "downloading_incremental_snapshot_total_bytes", gui->summary.startup_progress.startup_incremental_snapshot_total_bytes );
583 0 : jsonp_ulong( gui->http, "downloading_incremental_snapshot_current_bytes", gui->summary.startup_progress.startup_incremental_snapshot_current_bytes );
584 0 : } else {
585 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_peer" );
586 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_slot" );
587 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_elapsed_secs" );
588 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_remaining_secs" );
589 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_throughput" );
590 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_total_bytes" );
591 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_current_bytes" );
592 0 : }
593 :
594 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUIH_START_PROGRESS_TYPE_PROCESSING_LEDGER) ) {
595 0 : jsonp_ulong( gui->http, "ledger_slot", gui->summary.startup_progress.startup_ledger_slot );
596 0 : jsonp_ulong( gui->http, "ledger_max_slot", gui->summary.startup_progress.startup_ledger_max_slot );
597 0 : } else {
598 0 : jsonp_null( gui->http, "ledger_slot" );
599 0 : jsonp_null( gui->http, "ledger_max_slot" );
600 0 : }
601 :
602 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUIH_START_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY ) && gui->summary.startup_progress.startup_waiting_for_supermajority_slot!=ULONG_MAX ) {
603 0 : jsonp_ulong( gui->http, "waiting_for_supermajority_slot", gui->summary.startup_progress.startup_waiting_for_supermajority_slot );
604 0 : jsonp_ulong( gui->http, "waiting_for_supermajority_stake_percent", gui->summary.startup_progress.startup_waiting_for_supermajority_stake_pct );
605 0 : } else {
606 0 : jsonp_null( gui->http, "waiting_for_supermajority_slot" );
607 0 : jsonp_null( gui->http, "waiting_for_supermajority_stake_percent" );
608 0 : }
609 0 : jsonp_close_object( gui->http );
610 0 : jsonp_close_envelope( gui->http );
611 0 : }
612 :
613 : void
614 0 : fd_guih_printf_block_engine( fd_guih_t * gui ) {
615 0 : jsonp_open_envelope( gui->http, "block_engine", "update" );
616 0 : jsonp_open_object( gui->http, "value" );
617 0 : jsonp_string( gui->http, "name", gui->block_engine.name );
618 0 : jsonp_string( gui->http, "url", gui->block_engine.url );
619 0 : jsonp_string( gui->http, "ip", gui->block_engine.ip_cstr );
620 0 : if( FD_LIKELY( gui->block_engine.status==FD_BUNDLE_STATE_CONNECTING ) ) jsonp_string( gui->http, "status", "connecting" );
621 0 : else if( FD_LIKELY( gui->block_engine.status==FD_BUNDLE_STATE_CONNECTED ) ) jsonp_string( gui->http, "status", "connected" );
622 0 : else if( FD_LIKELY( gui->block_engine.status==FD_BUNDLE_STATE_SLEEPING ) ) jsonp_string( gui->http, "status", "sleeping" );
623 0 : else jsonp_string( gui->http, "status", "disconnected" );
624 0 : jsonp_close_object( gui->http );
625 0 : jsonp_close_envelope( gui->http );
626 0 : }
627 :
628 : void
629 0 : fd_guih_printf_tiles( fd_guih_t * gui ) {
630 0 : jsonp_open_envelope( gui->http, "summary", "tiles" );
631 0 : jsonp_open_array( gui->http, "value" );
632 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
633 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
634 :
635 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
636 : /* bench tiles not reported */
637 0 : continue;
638 0 : }
639 :
640 0 : jsonp_open_object( gui->http, NULL );
641 0 : jsonp_string( gui->http, "kind", tile->name );
642 0 : jsonp_ulong( gui->http, "kind_id", tile->kind_id );
643 0 : jsonp_ulong( gui->http, "pid", fd_metrics_tile( tile->metrics )[ MIDX( GAUGE, TILE, PID ) ] );
644 0 : jsonp_close_object( gui->http );
645 0 : }
646 0 : jsonp_close_array( gui->http );
647 0 : jsonp_close_envelope( gui->http );
648 0 : }
649 :
650 : void
651 0 : fd_guih_printf_schedule_strategy( fd_guih_t * gui ) {
652 0 : jsonp_open_envelope( gui->http, "summary", "schedule_strategy" );
653 0 : char mode[10];
654 0 : switch (gui->summary.schedule_strategy) {
655 0 : case 0: strncpy( mode, "perf", sizeof(mode) ); break;
656 0 : case 1: strncpy( mode, "balanced", sizeof(mode) ); break;
657 0 : case 2: strncpy( mode, "revenue", sizeof(mode) ); break;
658 0 : default: FD_LOG_ERR(("unexpected schedule_strategy %d", gui->summary.schedule_strategy));
659 0 : }
660 0 : mode[ sizeof(mode) - 1] = '\0';
661 0 : jsonp_string( gui->http, "value", mode );
662 0 : jsonp_close_envelope( gui->http );
663 0 : }
664 :
665 : void
666 0 : fd_guih_printf_identity_balance( fd_guih_t * gui ) {
667 0 : jsonp_open_envelope( gui->http, "summary", "identity_balance" );
668 0 : jsonp_ulong_as_str( gui->http, "value", gui->summary.identity_account_balance );
669 0 : jsonp_close_envelope( gui->http );
670 0 : }
671 :
672 : void
673 0 : fd_guih_printf_vote_balance( fd_guih_t * gui ) {
674 0 : jsonp_open_envelope( gui->http, "summary", "vote_balance" );
675 0 : jsonp_ulong_as_str( gui->http, "value", gui->summary.vote_account_balance );
676 0 : jsonp_close_envelope( gui->http );
677 0 : }
678 :
679 : void
680 0 : fd_guih_printf_estimated_slot_duration_nanos( fd_guih_t * gui ) {
681 0 : jsonp_open_envelope( gui->http, "summary", "estimated_slot_duration_nanos" );
682 0 : jsonp_ulong( gui->http, "value", gui->summary.estimated_slot_duration_nanos );
683 0 : jsonp_close_envelope( gui->http );
684 0 : }
685 :
686 :
687 : void
688 0 : fd_guih_printf_root_slot( fd_guih_t * gui ) {
689 0 : jsonp_open_envelope( gui->http, "summary", "root_slot" );
690 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_rooted!=ULONG_MAX, gui->summary.slot_rooted, 0UL ) );
691 0 : jsonp_close_envelope( gui->http );
692 0 : }
693 :
694 : void
695 0 : fd_guih_printf_optimistically_confirmed_slot( fd_guih_t * gui ) {
696 0 : jsonp_open_envelope( gui->http, "summary", "optimistically_confirmed_slot" );
697 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_optimistically_confirmed!=ULONG_MAX, gui->summary.slot_optimistically_confirmed, 0UL ) );
698 0 : jsonp_close_envelope( gui->http );
699 0 : }
700 :
701 : void
702 0 : fd_guih_printf_completed_slot( fd_guih_t * gui ) {
703 0 : jsonp_open_envelope( gui->http, "summary", "completed_slot" );
704 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_completed!=ULONG_MAX, gui->summary.slot_completed, 0UL ) );
705 0 : jsonp_close_envelope( gui->http );
706 0 : }
707 :
708 : void
709 0 : fd_guih_printf_estimated_slot( fd_guih_t * gui ) {
710 0 : jsonp_open_envelope( gui->http, "summary", "estimated_slot" );
711 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_estimated!=ULONG_MAX, gui->summary.slot_estimated, 0UL ) );
712 0 : jsonp_close_envelope( gui->http );
713 0 : }
714 :
715 : void
716 : fd_guih_printf_skip_rate( fd_guih_t * gui,
717 0 : ulong epoch_idx ) {
718 0 : jsonp_open_envelope( gui->http, "summary", "skip_rate" );
719 0 : jsonp_open_object( gui->http, "value" );
720 0 : jsonp_ulong( gui->http, "epoch", gui->epoch.epochs[ epoch_idx ].epoch );
721 0 : fd_http_server_printf( gui->http, "\"skip_rate\":%.7f,", !!gui->epoch.epochs[ epoch_idx ].my_total_slots ? (double)gui->epoch.epochs[ epoch_idx ].my_skipped_slots/(double)gui->epoch.epochs[ epoch_idx ].my_total_slots : 0.0 );
722 0 : jsonp_close_object( gui->http );
723 0 : jsonp_close_envelope( gui->http );
724 0 : }
725 :
726 : void
727 : fd_guih_printf_epoch( fd_guih_t * gui,
728 0 : ulong epoch_idx ) {
729 0 : jsonp_open_envelope( gui->http, "epoch", "new" );
730 0 : jsonp_open_object( gui->http, "value" );
731 0 : jsonp_ulong( gui->http, "epoch", gui->epoch.epochs[ epoch_idx ].epoch );
732 0 : if( FD_LIKELY( gui->epoch.epochs[ epoch_idx ].start_time!=LONG_MAX ) ) jsonp_ulong_as_str( gui->http, "start_time_nanos", (ulong)gui->epoch.epochs[ epoch_idx ].start_time );
733 0 : else jsonp_null( gui->http, "start_time_nanos" );
734 0 : if( FD_LIKELY( gui->epoch.epochs[ epoch_idx ].end_time!=LONG_MAX ) ) jsonp_ulong_as_str( gui->http, "end_time_nanos", (ulong)gui->epoch.epochs[ epoch_idx ].end_time );
735 0 : else jsonp_null( gui->http, "end_time_nanos" );
736 0 : jsonp_ulong( gui->http, "start_slot", gui->epoch.epochs[ epoch_idx ].start_slot );
737 0 : jsonp_ulong( gui->http, "end_slot", gui->epoch.epochs[ epoch_idx ].end_slot );
738 0 : jsonp_ulong_as_str( gui->http, "excluded_stake_lamports", 0UL );
739 0 : jsonp_open_array( gui->http, "staked_pubkeys" );
740 0 : fd_epoch_leaders_t * lsched = gui->epoch.epochs[epoch_idx].lsched;
741 0 : for( ulong i=0UL; i<lsched->pub_cnt; i++ ) {
742 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
743 0 : fd_base58_encode_32( lsched->pub[ i ].uc, NULL, identity_base58 );
744 0 : jsonp_string( gui->http, NULL, identity_base58 );
745 0 : }
746 0 : jsonp_close_array( gui->http );
747 :
748 0 : jsonp_open_array( gui->http, "staked_lamports" );
749 0 : fd_vote_stake_weight_t * stakes = gui->epoch.epochs[epoch_idx].stakes;
750 0 : for( ulong i=0UL; i<lsched->pub_cnt; i++ ) jsonp_ulong_as_str( gui->http, NULL, stakes[ i ].stake );
751 0 : jsonp_close_array( gui->http );
752 :
753 0 : jsonp_open_array( gui->http, "leader_slots" );
754 0 : for( ulong i = 0; i < lsched->sched_cnt; i++ ) jsonp_ulong( gui->http, NULL, lsched->sched[ i ] );
755 0 : jsonp_close_array( gui->http );
756 0 : jsonp_close_object( gui->http );
757 0 : jsonp_close_envelope( gui->http );
758 0 : }
759 :
760 : static void
761 : fd_guih_printf_waterfall( fd_guih_t * gui,
762 : fd_guih_txn_waterfall_t const * prev,
763 0 : fd_guih_txn_waterfall_t const * cur ) {
764 0 : jsonp_open_object( gui->http, "waterfall" );
765 0 : jsonp_open_object( gui->http, "in" );
766 0 : jsonp_ulong( gui->http, "pack_cranked", cur->in.pack_cranked - prev->in.pack_cranked );
767 0 : jsonp_ulong( gui->http, "pack_retained", prev->out.pack_retained );
768 0 : jsonp_ulong( gui->http, "resolv_retained", prev->out.resolv_retained );
769 0 : jsonp_ulong( gui->http, "quic", cur->in.quic - prev->in.quic );
770 0 : jsonp_ulong( gui->http, "udp", cur->in.udp - prev->in.udp );
771 0 : jsonp_ulong( gui->http, "gossip", cur->in.gossip - prev->in.gossip );
772 0 : jsonp_ulong( gui->http, "block_engine", cur->in.block_engine - prev->in.block_engine );
773 0 : jsonp_close_object( gui->http );
774 :
775 0 : jsonp_open_object( gui->http, "out" );
776 0 : jsonp_ulong( gui->http, "net_overrun", cur->out.net_overrun - prev->out.net_overrun );
777 0 : jsonp_ulong( gui->http, "quic_overrun", cur->out.quic_overrun - prev->out.quic_overrun );
778 0 : jsonp_ulong( gui->http, "quic_frag_drop", cur->out.quic_frag_drop - prev->out.quic_frag_drop );
779 0 : jsonp_ulong( gui->http, "quic_abandoned", cur->out.quic_abandoned - prev->out.quic_abandoned );
780 0 : jsonp_ulong( gui->http, "tpu_quic_invalid", cur->out.tpu_quic_invalid - prev->out.tpu_quic_invalid );
781 0 : jsonp_ulong( gui->http, "tpu_udp_invalid", cur->out.tpu_udp_invalid - prev->out.tpu_udp_invalid );
782 0 : jsonp_ulong( gui->http, "verify_overrun", cur->out.verify_overrun - prev->out.verify_overrun );
783 0 : jsonp_ulong( gui->http, "verify_parse", cur->out.verify_parse - prev->out.verify_parse );
784 0 : jsonp_ulong( gui->http, "verify_failed", cur->out.verify_failed - prev->out.verify_failed );
785 0 : jsonp_ulong( gui->http, "verify_duplicate", cur->out.verify_duplicate - prev->out.verify_duplicate );
786 0 : jsonp_ulong( gui->http, "dedup_duplicate", cur->out.dedup_duplicate - prev->out.dedup_duplicate );
787 0 : jsonp_ulong( gui->http, "resolv_lut_failed", cur->out.resolv_lut_failed - prev->out.resolv_lut_failed );
788 0 : jsonp_ulong( gui->http, "resolv_expired", cur->out.resolv_expired - prev->out.resolv_expired );
789 0 : jsonp_ulong( gui->http, "resolv_ancient", cur->out.resolv_ancient - prev->out.resolv_ancient );
790 0 : jsonp_ulong( gui->http, "resolv_no_ledger", cur->out.resolv_no_ledger - prev->out.resolv_no_ledger );
791 0 : jsonp_ulong( gui->http, "resolv_retained", cur->out.resolv_retained );
792 0 : jsonp_ulong( gui->http, "pack_invalid", cur->out.pack_invalid - prev->out.pack_invalid );
793 0 : jsonp_ulong( gui->http, "pack_invalid_bundle", cur->out.pack_invalid_bundle - prev->out.pack_invalid_bundle );
794 0 : jsonp_ulong( gui->http, "pack_expired", cur->out.pack_expired - prev->out.pack_expired );
795 0 : jsonp_ulong( gui->http, "pack_already_executed", cur->out.pack_already_executed - prev->out.pack_already_executed );
796 0 : jsonp_ulong( gui->http, "pack_retained", cur->out.pack_retained );
797 0 : jsonp_ulong( gui->http, "pack_wait_full", cur->out.pack_wait_full - prev->out.pack_wait_full );
798 0 : jsonp_ulong( gui->http, "pack_leader_slow", cur->out.pack_leader_slow - prev->out.pack_leader_slow );
799 0 : jsonp_ulong( gui->http, "bank_invalid", cur->out.bank_invalid - prev->out.bank_invalid );
800 0 : jsonp_ulong( gui->http, "bank_nonce_already_advanced", cur->out.bank_nonce_already_advanced - prev->out.bank_nonce_already_advanced );
801 0 : jsonp_ulong( gui->http, "bank_nonce_advance_failed", cur->out.bank_nonce_advance_failed - prev->out.bank_nonce_advance_failed );
802 0 : jsonp_ulong( gui->http, "bank_nonce_wrong_blockhash", cur->out.bank_nonce_wrong_blockhash - prev->out.bank_nonce_wrong_blockhash );
803 0 : jsonp_ulong( gui->http, "block_success", cur->out.block_success - prev->out.block_success );
804 0 : jsonp_ulong( gui->http, "block_fail", cur->out.block_fail - prev->out.block_fail );
805 0 : jsonp_close_object( gui->http );
806 0 : jsonp_close_object( gui->http );
807 0 : }
808 :
809 : void
810 : fd_guih_printf_live_txn_waterfall( fd_guih_t * gui,
811 : fd_guih_txn_waterfall_t const * prev,
812 : fd_guih_txn_waterfall_t const * cur,
813 0 : ulong next_leader_slot ) {
814 0 : jsonp_open_envelope( gui->http, "summary", "live_txn_waterfall" );
815 0 : jsonp_open_object( gui->http, "value" );
816 0 : jsonp_ulong( gui->http, "next_leader_slot", next_leader_slot );
817 0 : fd_guih_printf_waterfall( gui, prev, cur );
818 0 : jsonp_close_object( gui->http );
819 0 : jsonp_close_envelope( gui->http );
820 0 : }
821 :
822 : static void
823 : fd_guih_printf_network_metrics( fd_guih_t * gui,
824 0 : fd_guih_network_stats_t const * cur ) {
825 0 : jsonp_open_array( gui->http, "ingress" );
826 0 : jsonp_ulong( gui->http, NULL, cur->in.turbine );
827 0 : jsonp_ulong( gui->http, NULL, cur->in.gossip );
828 0 : jsonp_ulong( gui->http, NULL, cur->in.tpu );
829 0 : jsonp_ulong( gui->http, NULL, cur->in.repair );
830 0 : jsonp_ulong( gui->http, NULL, cur->in.rserve );
831 0 : jsonp_ulong( gui->http, NULL, cur->in.metric );
832 0 : jsonp_close_array( gui->http );
833 0 : jsonp_open_array( gui->http, "egress" );
834 0 : jsonp_ulong( gui->http, NULL, cur->out.turbine );
835 0 : jsonp_ulong( gui->http, NULL, cur->out.gossip );
836 0 : jsonp_ulong( gui->http, NULL, cur->out.tpu );
837 0 : jsonp_ulong( gui->http, NULL, cur->out.repair );
838 0 : jsonp_ulong( gui->http, NULL, cur->out.rserve );
839 0 : jsonp_ulong( gui->http, NULL, cur->out.metric );
840 0 : jsonp_close_array( gui->http );
841 0 : jsonp_open_array( gui->http, "ingress_ema" );
842 0 : for( ulong i=0UL; i<FD_GUIH_NET_PROTO_CNT; i++ ) jsonp_double( gui->http, NULL, fd_double_if( gui->summary.net_rate_ema_ready, gui->summary.ingress_ema[ i ], 0.0 ) );
843 0 : jsonp_close_array( gui->http );
844 0 : jsonp_open_array( gui->http, "egress_ema" );
845 0 : for( ulong i=0UL; i<FD_GUIH_NET_PROTO_CNT; i++ ) jsonp_double( gui->http, NULL, fd_double_if( gui->summary.net_rate_ema_ready, gui->summary.egress_ema[ i ], 0.0 ) );
846 0 : jsonp_close_array( gui->http );
847 0 : fd_guih_rate_entry_t const * ingress_max_head = fd_guih_rate_deque_empty( gui->summary.ingress_maxq ) ? NULL : fd_guih_rate_deque_peek_head_const( gui->summary.ingress_maxq );
848 0 : fd_guih_rate_entry_t const * egress_max_head = fd_guih_rate_deque_empty( gui->summary.egress_maxq ) ? NULL : fd_guih_rate_deque_peek_head_const( gui->summary.egress_maxq );
849 0 : jsonp_ulong( gui->http, "ingress_max_5m", ingress_max_head ? (ulong)ingress_max_head->value : 0UL );
850 0 : jsonp_ulong( gui->http, "egress_max_5m", egress_max_head ? (ulong)egress_max_head->value : 0UL );
851 0 : }
852 :
853 : void
854 : fd_guih_printf_live_network_metrics( fd_guih_t * gui,
855 0 : fd_guih_network_stats_t const * cur ) {
856 0 : jsonp_open_envelope( gui->http, "summary", "live_network_metrics" );
857 0 : jsonp_open_object( gui->http, "value" );
858 0 : fd_guih_printf_network_metrics( gui, cur );
859 0 : jsonp_close_object( gui->http );
860 0 : jsonp_close_envelope( gui->http );
861 0 : }
862 :
863 : static void
864 : fd_guih_printf_tile_stats( fd_guih_t * gui,
865 : fd_guih_tile_stats_t const * prev,
866 0 : fd_guih_tile_stats_t const * cur ) {
867 0 : jsonp_open_object( gui->http, "tile_primary_metric" );
868 0 : jsonp_ulong( gui->http, "quic", cur->quic_conn_cnt );
869 0 : jsonp_double( gui->http, "bundle_rtt_smoothed_millis", (double)(cur->bundle_rtt_smoothed_nanos) / 1000000.0 );
870 :
871 0 : fd_histf_t bundle_rx_delay_hist_delta[ 1 ];
872 0 : fd_histf_subtract( &cur->bundle_rx_delay_hist, &prev->bundle_rx_delay_hist, bundle_rx_delay_hist_delta );
873 0 : ulong bundle_rx_delay_nanos_p90 = fd_histf_percentile( bundle_rx_delay_hist_delta, 90U, ULONG_MAX );
874 0 : jsonp_double( gui->http, "bundle_rx_delay_millis_p90", fd_double_if(bundle_rx_delay_nanos_p90==ULONG_MAX, 0.0, (double)(bundle_rx_delay_nanos_p90) / 1000000.0 ));
875 :
876 0 : if( FD_LIKELY( cur->sample_time_nanos>prev->sample_time_nanos ) ) {
877 0 : jsonp_ulong( gui->http, "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) ));
878 0 : jsonp_ulong( gui->http, "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) ));
879 0 : } else {
880 0 : jsonp_ulong( gui->http, "net_in", 0 );
881 0 : jsonp_ulong( gui->http, "net_out", 0 );
882 0 : }
883 0 : if( FD_LIKELY( cur->verify_total_cnt>prev->verify_total_cnt ) ) {
884 0 : jsonp_double( gui->http, "verify", (double)(cur->verify_drop_cnt-prev->verify_drop_cnt) / (double)(cur->verify_total_cnt-prev->verify_total_cnt) );
885 0 : } else {
886 0 : jsonp_double( gui->http, "verify", 0.0 );
887 0 : }
888 0 : if( FD_LIKELY( cur->dedup_total_cnt>prev->dedup_total_cnt ) ) {
889 0 : jsonp_double( gui->http, "dedup", (double)(cur->dedup_drop_cnt-prev->dedup_drop_cnt) / (double)(cur->dedup_total_cnt-prev->dedup_total_cnt) );
890 0 : } else {
891 0 : jsonp_double( gui->http, "dedup", 0.0 );
892 0 : }
893 0 : jsonp_ulong( gui->http, "bank", cur->bank_txn_exec_cnt - prev->bank_txn_exec_cnt );
894 0 : jsonp_double( gui->http, "pack", !cur->pack_buffer_capacity ? 1.0 : (double)cur->pack_buffer_cnt/(double)cur->pack_buffer_capacity );
895 0 : jsonp_double( gui->http, "poh", 0.0 );
896 0 : jsonp_double( gui->http, "shred", 0.0 );
897 0 : jsonp_double( gui->http, "store", 0.0 );
898 0 : jsonp_close_object( gui->http );
899 0 : }
900 :
901 : void
902 : fd_guih_printf_live_tile_stats( fd_guih_t * gui,
903 : fd_guih_tile_stats_t const * prev,
904 0 : fd_guih_tile_stats_t const * cur ) {
905 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_primary_metric" );
906 0 : jsonp_open_object( gui->http, "value" );
907 0 : jsonp_ulong( gui->http, "next_leader_slot", 0UL );
908 0 : fd_guih_printf_tile_stats( gui, prev, cur );
909 0 : jsonp_close_object( gui->http );
910 0 : jsonp_close_envelope( gui->http );
911 0 : }
912 :
913 : static void
914 : fd_guih_printf_tile_timers( fd_guih_t * gui,
915 : fd_guih_tile_timers_t const * prev,
916 0 : fd_guih_tile_timers_t const * cur ) {
917 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
918 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
919 :
920 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
921 : /* bench tiles not reported */
922 0 : continue;
923 0 : }
924 :
925 0 : ulong cur_total = 0UL;
926 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++ ) cur_total += cur[ i ].timers[ j ];
927 :
928 0 : ulong prev_total = 0UL;
929 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++ ) prev_total += prev[ i ].timers[ j ];
930 :
931 0 : double idle_ratio;
932 0 : if( FD_UNLIKELY( cur_total==prev_total ) ) {
933 : /* The tile didn't sample timers since the last sample, unclear what
934 : idleness should be so send -1. NaN would be better but no NaN in
935 : JSON. */
936 0 : idle_ratio = -1;
937 0 : } else {
938 0 : ulong idle_time = cur[ i ].timers[ FD_METRICS_ENUM_TILE_REGIME_V_CAUGHT_UP_POSTFRAG_IDX ] - prev[ i ].timers[ FD_METRICS_ENUM_TILE_REGIME_V_CAUGHT_UP_POSTFRAG_IDX ];
939 0 : ulong backpressure_time = cur[ i ].timers[ FD_METRICS_ENUM_TILE_REGIME_V_BACKPRESSURE_PREFRAG_IDX ] - prev[ i ].timers[ FD_METRICS_ENUM_TILE_REGIME_V_BACKPRESSURE_PREFRAG_IDX ];
940 0 : idle_ratio = (double)(idle_time+backpressure_time) / (double)(cur_total - prev_total);
941 0 : }
942 :
943 0 : jsonp_double( gui->http, NULL, idle_ratio );
944 0 : }
945 0 : }
946 :
947 : static void
948 : fd_guih_printf_tile_metrics( fd_guih_t * gui,
949 : fd_guih_tile_timers_t const * prev,
950 0 : fd_guih_tile_timers_t const * cur ) {
951 0 : jsonp_open_array( gui->http, "timers" );
952 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
953 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
954 :
955 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
956 : /* bench tiles not reported */
957 0 : jsonp_null( gui->http, NULL );
958 0 : continue;
959 0 : }
960 :
961 0 : ulong cur_total = 0UL;
962 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++ ) cur_total += cur[ i ].timers[ j ];
963 :
964 0 : ulong prev_total = 0UL;
965 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++ ) prev_total += prev[ i ].timers[ j ];
966 :
967 0 : if( FD_UNLIKELY( cur_total==prev_total ) ) {
968 0 : jsonp_null( gui->http, NULL );
969 0 : } else {
970 0 : jsonp_open_array( gui->http, NULL );
971 0 : for (ulong j = 0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++) {
972 0 : double percent = ((double)(cur[ i ].timers[ j ] - prev[ i ].timers[ j ]) / (double)(cur_total-prev_total)) * 100.0;
973 0 : double percent_trunc = (double)((long)(percent * 100.0)) / 100.0;
974 0 : jsonp_double( gui->http, NULL, percent_trunc );
975 0 : }
976 0 : jsonp_close_array( gui->http );
977 0 : }
978 0 : }
979 0 : jsonp_close_array( gui->http );
980 :
981 0 : jsonp_open_array( gui->http, "sched_timers" );
982 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
983 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
984 :
985 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
986 : /* bench tiles not reported */
987 0 : jsonp_null( gui->http, NULL );
988 0 : continue;
989 0 : }
990 :
991 0 : ulong cur_total = 0UL;
992 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_CPU_REGIME_CNT; j++ ) cur_total += cur[ i ].sched_timers[ j ];
993 :
994 0 : ulong prev_total = 0UL;
995 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_CPU_REGIME_CNT; j++ ) prev_total += prev[ i ].sched_timers[ j ];
996 :
997 0 : if( FD_UNLIKELY( cur_total==prev_total ) ) {
998 0 : jsonp_null( gui->http, NULL );
999 0 : } else {
1000 0 : jsonp_open_array( gui->http, NULL );
1001 0 : for (ulong j = 0UL; j<FD_METRICS_ENUM_CPU_REGIME_CNT; j++) {
1002 0 : double percent = ((double)(cur[ i ].sched_timers[ j ] - prev[ i ].sched_timers[ j ]) / (double)(cur_total-prev_total)) * 100.0;
1003 0 : double percent_trunc = (double)((long)(percent * 100.0)) / 100.0;
1004 0 : jsonp_double( gui->http, NULL, percent_trunc );
1005 0 : }
1006 0 : jsonp_close_array( gui->http );
1007 0 : }
1008 0 : }
1009 0 : jsonp_close_array( gui->http );
1010 :
1011 0 : jsonp_open_array( gui->http, "in_backp" );
1012 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1013 0 : jsonp_bool( gui->http, NULL, cur[ i ].in_backp );
1014 0 : }
1015 0 : jsonp_close_array( gui->http );
1016 0 : jsonp_open_array( gui->http, "backp_msgs" );
1017 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1018 0 : jsonp_ulong( gui->http, NULL, cur[ i ].backp_cnt );
1019 0 : }
1020 0 : jsonp_close_array( gui->http );
1021 0 : jsonp_open_array( gui->http, "alive" );
1022 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1023 : /* We use a longer sampling window for this metric to minimize
1024 : false positives */
1025 0 : jsonp_ulong( gui->http, NULL, fd_ulong_if( cur[ i ].status==2U, 2UL, (ulong)(cur[ i ].heartbeat>prev[ i ].heartbeat) ) );
1026 0 : }
1027 0 : jsonp_close_array( gui->http );
1028 0 : jsonp_open_array( gui->http, "nvcsw" );
1029 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1030 0 : jsonp_ulong( gui->http, NULL, cur[ i ].nvcsw );
1031 0 : }
1032 0 : jsonp_close_array( gui->http );
1033 0 : jsonp_open_array( gui->http, "nivcsw" );
1034 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1035 0 : jsonp_ulong( gui->http, NULL, cur[ i ].nivcsw );
1036 0 : }
1037 0 : jsonp_close_array( gui->http );
1038 0 : jsonp_open_array( gui->http, "minflt" );
1039 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1040 0 : jsonp_ulong( gui->http, NULL, cur[ i ].minflt );
1041 0 : }
1042 0 : jsonp_close_array( gui->http );
1043 0 : jsonp_open_array( gui->http, "majflt" );
1044 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1045 0 : jsonp_ulong( gui->http, NULL, cur[ i ].majflt );
1046 0 : }
1047 0 : jsonp_close_array( gui->http );
1048 0 : jsonp_open_array( gui->http, "last_cpu" );
1049 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1050 0 : jsonp_ulong( gui->http, NULL, cur[ i ].last_cpu );
1051 0 : }
1052 0 : jsonp_close_array( gui->http );
1053 0 : jsonp_open_array( gui->http, "interrupts" );
1054 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1055 0 : jsonp_ulong( gui->http, NULL, cur[ i ].interrupts );
1056 0 : }
1057 0 : jsonp_close_array( gui->http );
1058 0 : jsonp_open_array( gui->http, "priority" );
1059 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1060 0 : int priority = fd_topob_tile_priority_type( gui->topo->tiles[ i ].name );
1061 :
1062 0 : char const * priority_type_str = "unknown";
1063 0 : switch( priority ) {
1064 0 : case FD_TOPOB_PRIORITY_FLOATING: priority_type_str = "floating"; break;
1065 0 : case FD_TOPOB_PRIORITY_STARTUP: priority_type_str = "startup"; break;
1066 0 : case FD_TOPOB_PRIORITY_NORMAL: priority_type_str = "normal"; break;
1067 0 : case FD_TOPOB_PRIORITY_CRITICAL: priority_type_str = "critical"; break;
1068 0 : }
1069 :
1070 0 : jsonp_string( gui->http, NULL, priority_type_str );
1071 0 : }
1072 0 : jsonp_close_array( gui->http );
1073 0 : }
1074 :
1075 : void
1076 0 : fd_guih_printf_live_tile_timers( fd_guih_t * gui ) {
1077 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_timers" );
1078 0 : jsonp_open_array( gui->http, "value" );
1079 0 : fd_guih_tile_timers_t * cur = gui->summary.tile_timers_snap + ((gui->summary.tile_timers_snap_idx+(FD_GUIH_TILE_TIMER_SNAP_CNT-1UL))%FD_GUIH_TILE_TIMER_SNAP_CNT) * gui->tile_cnt;
1080 0 : fd_guih_tile_timers_t * prev = gui->summary.tile_timers_snap + ((gui->summary.tile_timers_snap_idx+(FD_GUIH_TILE_TIMER_SNAP_CNT-2UL))%FD_GUIH_TILE_TIMER_SNAP_CNT) * gui->tile_cnt;
1081 0 : fd_guih_printf_tile_timers( gui, prev, cur );
1082 0 : jsonp_close_array( gui->http );
1083 0 : jsonp_close_envelope( gui->http );
1084 0 : }
1085 :
1086 : void
1087 0 : fd_guih_printf_live_tile_metrics( fd_guih_t * gui ) {
1088 0 : fd_guih_tile_timers_t * cur = gui->summary.tile_timers_snap + ((gui->summary.tile_timers_snap_idx+(FD_GUIH_TILE_TIMER_SNAP_CNT-1UL))%FD_GUIH_TILE_TIMER_SNAP_CNT) * gui->tile_cnt;
1089 0 : fd_guih_tile_timers_t * prev = gui->summary.tile_timers_snap + ((gui->summary.tile_timers_snap_idx+(FD_GUIH_TILE_TIMER_SNAP_CNT-2UL))%FD_GUIH_TILE_TIMER_SNAP_CNT) * gui->tile_cnt;
1090 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_metrics" );
1091 0 : jsonp_open_object( gui->http, "value" );
1092 0 : fd_guih_printf_tile_metrics( gui, prev, cur );
1093 0 : jsonp_close_object( gui->http );
1094 0 : jsonp_close_envelope( gui->http );
1095 0 : }
1096 :
1097 : void
1098 0 : fd_guih_printf_estimated_tps( fd_guih_t * gui ) {
1099 0 : ulong idx = (gui->summary.estimated_tps_history_idx+FD_GUIH_TPS_HISTORY_SAMPLE_CNT-1UL) % FD_GUIH_TPS_HISTORY_SAMPLE_CNT;
1100 :
1101 0 : jsonp_open_envelope( gui->http, "summary", "estimated_tps" );
1102 0 : jsonp_open_object( gui->http, "value" );
1103 0 : ulong vote_cnt = gui->summary.estimated_tps_history[ idx ].vote_failed
1104 0 : + gui->summary.estimated_tps_history[ idx ].vote_success;
1105 0 : ulong total_cnt = vote_cnt
1106 0 : + gui->summary.estimated_tps_history[ idx ].nonvote_success
1107 0 : + gui->summary.estimated_tps_history[ idx ].nonvote_failed;
1108 0 : jsonp_double( gui->http, "total", (double)total_cnt/(double)FD_GUIH_TPS_HISTORY_WINDOW_DURATION_SECONDS );
1109 0 : jsonp_double( gui->http, "vote", (double)vote_cnt/(double)FD_GUIH_TPS_HISTORY_WINDOW_DURATION_SECONDS );
1110 0 : jsonp_double( gui->http, "nonvote_success", (double)gui->summary.estimated_tps_history[ idx ].nonvote_success/(double)FD_GUIH_TPS_HISTORY_WINDOW_DURATION_SECONDS );
1111 0 : jsonp_double( gui->http, "nonvote_failed", (double)gui->summary.estimated_tps_history[ idx ].nonvote_failed/(double)FD_GUIH_TPS_HISTORY_WINDOW_DURATION_SECONDS );
1112 0 : jsonp_close_object( gui->http );
1113 0 : jsonp_close_envelope( gui->http );
1114 0 : }
1115 :
1116 : void
1117 0 : fd_guih_printf_health( fd_guih_t * gui ) {
1118 0 : fd_topo_t const * topo = gui->topo;
1119 :
1120 0 : ulong diag_tile_idx = fd_topo_find_tile( topo, "diag", 0UL );
1121 :
1122 : /* Default to disabled if no diag tile */
1123 0 : ulong bundle_status = FD_DIAG_BUNDLE_STATUS_DISABLED;
1124 0 : ulong vote_status = FD_DIAG_VOTE_STATUS_DISABLED;
1125 0 : ulong replay_status = FD_DIAG_REPLAY_STATUS_DISABLED;
1126 0 : ulong turbine_status = FD_DIAG_TURBINE_STATUS_DISABLED;
1127 :
1128 0 : if( FD_LIKELY( diag_tile_idx!=ULONG_MAX ) ) {
1129 0 : volatile ulong const * metrics = fd_metrics_tile( topo->tiles[ diag_tile_idx ].metrics );
1130 0 : bundle_status = metrics[ MIDX( GAUGE, DIAG, BUNDLE_STATUS ) ];
1131 0 : vote_status = metrics[ MIDX( GAUGE, DIAG, VOTE_STATUS ) ];
1132 0 : replay_status = metrics[ MIDX( GAUGE, DIAG, REPLAY_STATUS ) ];
1133 0 : turbine_status = metrics[ MIDX( GAUGE, DIAG, TURBINE_STATUS ) ];
1134 0 : }
1135 :
1136 0 : if( FD_UNLIKELY( !gui->summary.is_full_client ) ) {
1137 0 : switch( gui->summary.vote_state ) {
1138 0 : case FD_GUIH_VOTE_STATE_VOTING: vote_status = FD_DIAG_VOTE_STATUS_VOTING; break;
1139 0 : case FD_GUIH_VOTE_STATE_DELINQUENT: vote_status = FD_DIAG_VOTE_STATUS_DELINQUENT; break;
1140 0 : default: vote_status = FD_DIAG_VOTE_STATUS_DISABLED; break;
1141 0 : }
1142 0 : replay_status = FD_DIAG_REPLAY_STATUS_DISABLED;
1143 0 : turbine_status = FD_DIAG_TURBINE_STATUS_DISABLED;
1144 0 : }
1145 :
1146 : /* Map bundle status to string */
1147 0 : char const * bundle_str;
1148 0 : switch( bundle_status ) {
1149 0 : case FD_DIAG_BUNDLE_STATUS_DISCONNECTED: bundle_str = "disconnected"; break;
1150 0 : case FD_DIAG_BUNDLE_STATUS_CONNECTING: bundle_str = "connecting"; break;
1151 0 : case FD_DIAG_BUNDLE_STATUS_CONNECTED: bundle_str = "connected"; break;
1152 0 : case FD_DIAG_BUNDLE_STATUS_SLEEPING: bundle_str = "sleeping"; break;
1153 0 : default: bundle_str = "disabled"; break;
1154 0 : }
1155 :
1156 : /* Map vote status to string */
1157 0 : char const * vote_str;
1158 0 : switch( vote_status ) {
1159 0 : case FD_DIAG_VOTE_STATUS_NOT_STARTED: vote_str = "not_started"; break;
1160 0 : case FD_DIAG_VOTE_STATUS_DELINQUENT: vote_str = "delinquent"; break;
1161 0 : case FD_DIAG_VOTE_STATUS_VOTING: vote_str = "voting"; break;
1162 0 : default: vote_str = "disabled"; break;
1163 0 : }
1164 :
1165 : /* Map replay status to string */
1166 0 : char const * replay_str;
1167 0 : switch( replay_status ) {
1168 0 : case FD_DIAG_REPLAY_STATUS_NOT_STARTED: replay_str = "not_started"; break;
1169 0 : case FD_DIAG_REPLAY_STATUS_BEHIND: replay_str = "behind"; break;
1170 0 : case FD_DIAG_REPLAY_STATUS_RUNNING: replay_str = "running"; break;
1171 0 : default: replay_str = "disabled"; break;
1172 0 : }
1173 :
1174 : /* Map turbine status to string */
1175 0 : char const * turbine_str;
1176 0 : switch( turbine_status ) {
1177 0 : case FD_DIAG_TURBINE_STATUS_NOT_STARTED: turbine_str = "not_started"; break;
1178 0 : case FD_DIAG_TURBINE_STATUS_STALLED: turbine_str = "stalled"; break;
1179 0 : case FD_DIAG_TURBINE_STATUS_REPAIR_OUTPACING: turbine_str = "repair_outpacing"; break;
1180 0 : case FD_DIAG_TURBINE_STATUS_RUNNING: turbine_str = "running"; break;
1181 0 : default: turbine_str = "disabled"; break;
1182 0 : }
1183 :
1184 0 : jsonp_open_envelope( gui->http, "summary", "health" );
1185 0 : jsonp_open_object( gui->http, "value" );
1186 0 : jsonp_string( gui->http, "vote", vote_str );
1187 0 : jsonp_string( gui->http, "bundle", bundle_str );
1188 0 : jsonp_string( gui->http, "replay", replay_str );
1189 0 : jsonp_string( gui->http, "turbine", turbine_str );
1190 0 : jsonp_close_object( gui->http );
1191 0 : jsonp_close_envelope( gui->http );
1192 0 : }
1193 :
1194 : static int
1195 : fd_guih_gossip_contains( fd_guih_t const * gui,
1196 0 : uchar const * pubkey ) {
1197 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
1198 0 : if( FD_UNLIKELY( !memcmp( gui->gossip.peers[ i ].pubkey->uc, pubkey, 32 ) ) ) return 1;
1199 0 : }
1200 0 : return 0;
1201 0 : }
1202 :
1203 : static int
1204 : fd_guih_vote_acct_contains( fd_guih_t const * gui,
1205 0 : uchar const * pubkey ) {
1206 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
1207 0 : if( FD_UNLIKELY( !memcmp( gui->vote_account.vote_accounts[ i ].pubkey, pubkey, 32 ) ) ) return 1;
1208 0 : }
1209 0 : return 0;
1210 0 : }
1211 :
1212 : static int
1213 : fd_guih_validator_info_contains( fd_guih_t const * gui,
1214 0 : uchar const * pubkey ) {
1215 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
1216 0 : if( FD_UNLIKELY( !memcmp( gui->validator_info.info[ i ].pubkey, pubkey, 32 ) ) ) return 1;
1217 0 : }
1218 0 : return 0;
1219 0 : }
1220 :
1221 : static void
1222 : fd_guih_printf_peer( fd_guih_t * gui,
1223 0 : uchar const * identity_pubkey ) {
1224 0 : ulong gossip_idx = ULONG_MAX;
1225 0 : ulong info_idx = ULONG_MAX;
1226 0 : ulong vote_idxs[ FD_GUIH_MAX_PEER_CNT ] = {0};
1227 0 : ulong vote_idx_cnt = 0UL;
1228 :
1229 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
1230 0 : if( FD_UNLIKELY( !memcmp( gui->gossip.peers[ i ].pubkey->uc, identity_pubkey, 32 ) ) ) {
1231 0 : gossip_idx = i;
1232 0 : break;
1233 0 : }
1234 0 : }
1235 :
1236 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
1237 0 : if( FD_UNLIKELY( !memcmp( gui->validator_info.info[ i ].pubkey, identity_pubkey, 32 ) ) ) {
1238 0 : info_idx = i;
1239 0 : break;
1240 0 : }
1241 0 : }
1242 :
1243 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
1244 0 : if( FD_UNLIKELY( !memcmp( gui->vote_account.vote_accounts[ i ].pubkey, identity_pubkey, 32 ) ) ) {
1245 0 : vote_idxs[ vote_idx_cnt++ ] = i;
1246 0 : }
1247 0 : }
1248 :
1249 0 : jsonp_open_object( gui->http, NULL );
1250 :
1251 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1252 0 : fd_base58_encode_32( identity_pubkey, NULL, identity_base58 );
1253 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
1254 :
1255 0 : if( FD_UNLIKELY( gossip_idx==ULONG_MAX ) ) {
1256 0 : jsonp_string( gui->http, "gossip", NULL );
1257 0 : } else {
1258 0 : jsonp_open_object( gui->http, "gossip" );
1259 :
1260 0 : char version[ 64UL ];
1261 0 : FD_TEST( fd_gossip_version_cstr( gui->gossip.peers[ gossip_idx ].version.major, gui->gossip.peers[ gossip_idx ].version.minor, gui->gossip.peers[ gossip_idx ].version.patch, version, sizeof( version ) ) );
1262 0 : jsonp_string( gui->http, "version", version );
1263 0 : jsonp_null( gui->http, "client_id" ); /* TODO: Frankendancer support */
1264 0 : jsonp_ulong( gui->http, "feature_set", gui->gossip.peers[ gossip_idx ].version.feature_set );
1265 0 : jsonp_ulong( gui->http, "wallclock", gui->gossip.peers[ gossip_idx ].wallclock );
1266 0 : jsonp_ulong( gui->http, "shred_version", gui->gossip.peers[ gossip_idx ].shred_version );
1267 0 : jsonp_open_object( gui->http, "sockets" );
1268 0 : for( ulong j=0UL; j<12UL; j++ ) {
1269 0 : if( FD_LIKELY( !gui->gossip.peers[ gossip_idx ].sockets[ j ].ipv4 && !gui->gossip.peers[ gossip_idx ].sockets[ j ].port ) ) continue;
1270 0 : char const * tag;
1271 0 : switch( j ) {
1272 0 : case 0: tag = "gossip"; break;
1273 0 : case 1: tag = "rpc"; break;
1274 0 : case 2: tag = "rpc_pubsub"; break;
1275 0 : case 3: tag = "serve_repair"; break;
1276 0 : case 4: tag = "serve_repair_quic"; break;
1277 0 : case 5: tag = "tpu"; break;
1278 0 : case 6: tag = "tpu_quic"; break;
1279 0 : case 7: tag = "tvu"; break;
1280 0 : case 8: tag = "tvu_quic"; break;
1281 0 : case 9: tag = "tpu_forwards"; break;
1282 0 : case 10: tag = "tpu_forwards_quic"; break;
1283 0 : case 11: tag = "tpu_vote"; break;
1284 0 : }
1285 0 : char line[ 64 ];
1286 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 ) );
1287 0 : jsonp_string( gui->http, tag, line );
1288 0 : }
1289 0 : jsonp_close_object( gui->http );
1290 :
1291 0 : jsonp_close_object( gui->http );
1292 0 : }
1293 :
1294 0 : jsonp_open_array( gui->http, "vote" );
1295 0 : ulong vote_idx_cnt_bounded = fd_ulong_min( vote_idx_cnt, 5UL );
1296 0 : for( ulong i=0UL; i<vote_idx_cnt_bounded; i++ ) {
1297 0 : jsonp_open_object( gui->http, NULL );
1298 0 : char vote_account_base58[ FD_BASE58_ENCODED_32_SZ ];
1299 0 : fd_base58_encode_32( gui->vote_account.vote_accounts[ vote_idxs[ i ] ].vote_account->uc, NULL, vote_account_base58 );
1300 0 : jsonp_string( gui->http, "vote_account", vote_account_base58 );
1301 0 : jsonp_ulong_as_str( gui->http, "activated_stake", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].activated_stake );
1302 0 : jsonp_ulong( gui->http, "last_vote", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].last_vote );
1303 0 : jsonp_ulong( gui->http, "root_slot", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].root_slot );
1304 0 : jsonp_ulong( gui->http, "epoch_credits", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].epoch_credits );
1305 0 : jsonp_ulong( gui->http, "commission", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].commission );
1306 0 : jsonp_bool( gui->http, "delinquent", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].delinquent );
1307 0 : jsonp_close_object( gui->http );
1308 0 : }
1309 0 : jsonp_close_array( gui->http );
1310 :
1311 0 : if( FD_UNLIKELY( info_idx==ULONG_MAX ) ) {
1312 0 : jsonp_string( gui->http, "info", NULL );
1313 0 : } else {
1314 0 : jsonp_open_object( gui->http, "info" );
1315 0 : jsonp_string( gui->http, "name", gui->validator_info.info[ info_idx ].name );
1316 0 : jsonp_string( gui->http, "details", gui->validator_info.info[ info_idx ].details );
1317 0 : jsonp_string( gui->http, "website", gui->validator_info.info[ info_idx ].website );
1318 0 : jsonp_string( gui->http, "icon_url", gui->validator_info.info[ info_idx ].icon_uri );
1319 0 : jsonp_string( gui->http, "keybase_username", "" );
1320 0 : jsonp_close_object( gui->http );
1321 0 : }
1322 :
1323 0 : jsonp_close_object( gui->http );
1324 0 : }
1325 :
1326 : void
1327 : fd_guih_printf_peers_gossip_update( fd_guih_t * gui,
1328 : ulong const * updated,
1329 : ulong updated_cnt,
1330 : fd_pubkey_t const * removed,
1331 : ulong removed_cnt,
1332 : ulong const * added,
1333 0 : ulong added_cnt ) {
1334 0 : jsonp_open_envelope( gui->http, "peers", "update" );
1335 0 : jsonp_open_object( gui->http, "value" );
1336 0 : jsonp_open_array( gui->http, "add" );
1337 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1338 0 : int actually_added = !fd_guih_vote_acct_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc ) &&
1339 0 : !fd_guih_validator_info_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
1340 0 : if( FD_LIKELY( !actually_added ) ) continue;
1341 :
1342 0 : fd_guih_printf_peer( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
1343 0 : }
1344 0 : jsonp_close_array( gui->http );
1345 :
1346 0 : jsonp_open_array( gui->http, "update" );
1347 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1348 0 : int actually_added = !fd_guih_vote_acct_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc ) &&
1349 0 : !fd_guih_validator_info_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
1350 0 : if( FD_LIKELY( actually_added ) ) continue;
1351 :
1352 0 : fd_guih_printf_peer( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
1353 0 : }
1354 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
1355 0 : fd_guih_printf_peer( gui, gui->gossip.peers[ updated[ i ] ].pubkey->uc );
1356 0 : }
1357 0 : jsonp_close_array( gui->http );
1358 :
1359 0 : jsonp_open_array( gui->http, "remove" );
1360 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
1361 0 : int actually_removed = !fd_guih_vote_acct_contains( gui, removed[ i ].uc ) &&
1362 0 : !fd_guih_validator_info_contains( gui, removed[ i ].uc );
1363 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
1364 :
1365 0 : jsonp_open_object( gui->http, NULL );
1366 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1367 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
1368 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
1369 0 : jsonp_close_object( gui->http );
1370 0 : }
1371 0 : jsonp_close_array( gui->http );
1372 0 : jsonp_close_object( gui->http );
1373 0 : jsonp_close_envelope( gui->http );
1374 0 : }
1375 :
1376 : void
1377 : fd_guih_printf_peers_vote_account_update( fd_guih_t * gui,
1378 : ulong const * updated,
1379 : ulong updated_cnt,
1380 : fd_pubkey_t const * removed,
1381 : ulong removed_cnt,
1382 : ulong const * added,
1383 0 : ulong added_cnt ) {
1384 0 : jsonp_open_envelope( gui->http, "peers", "update" );
1385 0 : jsonp_open_object( gui->http, "value" );
1386 0 : jsonp_open_array( gui->http, "add" );
1387 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1388 0 : int actually_added = !fd_guih_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
1389 0 : !fd_guih_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
1390 0 : if( FD_LIKELY( !actually_added ) ) continue;
1391 :
1392 0 : fd_guih_printf_peer( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
1393 0 : }
1394 0 : jsonp_close_array( gui->http );
1395 :
1396 0 : jsonp_open_array( gui->http, "update" );
1397 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1398 0 : int actually_added = !fd_guih_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
1399 0 : !fd_guih_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
1400 0 : if( FD_LIKELY( actually_added ) ) continue;
1401 :
1402 0 : fd_guih_printf_peer( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
1403 0 : }
1404 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
1405 0 : fd_guih_printf_peer( gui, gui->vote_account.vote_accounts[ updated[ i ] ].pubkey->uc );
1406 0 : }
1407 0 : jsonp_close_array( gui->http );
1408 :
1409 0 : jsonp_open_array( gui->http, "remove" );
1410 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
1411 0 : int actually_removed = !fd_guih_gossip_contains( gui, removed[ i ].uc) &&
1412 0 : !fd_guih_validator_info_contains( gui, removed[ i ].uc);
1413 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
1414 :
1415 0 : jsonp_open_object( gui->http, NULL );
1416 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1417 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
1418 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
1419 0 : jsonp_close_object( gui->http );
1420 0 : }
1421 0 : jsonp_close_array( gui->http );
1422 0 : jsonp_close_object( gui->http );
1423 0 : jsonp_close_envelope( gui->http );
1424 0 : }
1425 :
1426 : void
1427 : fd_guih_printf_peers_validator_info_update( fd_guih_t * gui,
1428 : ulong const * updated,
1429 : ulong updated_cnt,
1430 : fd_pubkey_t const * removed,
1431 : ulong removed_cnt,
1432 : ulong const * added,
1433 0 : ulong added_cnt ) {
1434 0 : jsonp_open_envelope( gui->http, "peers", "update" );
1435 0 : jsonp_open_object( gui->http, "value" );
1436 0 : jsonp_open_array( gui->http, "add" );
1437 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1438 0 : int actually_added = !fd_guih_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
1439 0 : !fd_guih_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1440 0 : if( FD_LIKELY( !actually_added ) ) continue;
1441 :
1442 0 : fd_guih_printf_peer( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1443 0 : }
1444 0 : jsonp_close_array( gui->http );
1445 :
1446 0 : jsonp_open_array( gui->http, "update" );
1447 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1448 0 : int actually_added = !fd_guih_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
1449 0 : !fd_guih_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1450 0 : if( FD_LIKELY( actually_added ) ) continue;
1451 :
1452 0 : fd_guih_printf_peer( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1453 0 : }
1454 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
1455 0 : fd_guih_printf_peer( gui, gui->validator_info.info[ updated[ i ] ].pubkey->uc );
1456 0 : }
1457 0 : jsonp_close_array( gui->http );
1458 :
1459 0 : jsonp_open_array( gui->http, "remove" );
1460 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
1461 0 : int actually_removed = !fd_guih_gossip_contains( gui, removed[ i ].uc ) &&
1462 0 : !fd_guih_vote_acct_contains( gui, removed[ i ].uc );
1463 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
1464 :
1465 0 : jsonp_open_object( gui->http, NULL );
1466 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1467 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
1468 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
1469 0 : jsonp_close_object( gui->http );
1470 0 : }
1471 0 : jsonp_close_array( gui->http );
1472 0 : jsonp_close_object( gui->http );
1473 0 : jsonp_close_envelope( gui->http );
1474 0 : }
1475 :
1476 : void
1477 0 : fd_guih_printf_peers_all( fd_guih_t * gui ) {
1478 0 : jsonp_open_envelope( gui->http, "peers", "update" );
1479 0 : jsonp_open_object( gui->http, "value" );
1480 0 : jsonp_open_array( gui->http, "add" );
1481 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
1482 0 : fd_guih_printf_peer( gui, gui->gossip.peers[ i ].pubkey->uc );
1483 0 : }
1484 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
1485 0 : int actually_added = !fd_guih_gossip_contains( gui, gui->vote_account.vote_accounts[ i ].pubkey->uc );
1486 0 : if( FD_UNLIKELY( actually_added ) ) {
1487 0 : fd_guih_printf_peer( gui, gui->vote_account.vote_accounts[ i ].pubkey->uc );
1488 0 : }
1489 0 : }
1490 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
1491 0 : int actually_added = !fd_guih_gossip_contains( gui, gui->validator_info.info[ i ].pubkey->uc ) &&
1492 0 : !fd_guih_vote_acct_contains( gui, gui->validator_info.info[ i ].pubkey->uc );
1493 0 : if( FD_UNLIKELY( actually_added ) ) {
1494 0 : fd_guih_printf_peer( gui, gui->validator_info.info[ i ].pubkey->uc );
1495 0 : }
1496 0 : }
1497 0 : jsonp_close_array( gui->http );
1498 0 : jsonp_close_object( gui->http );
1499 0 : jsonp_close_envelope( gui->http );
1500 0 : }
1501 :
1502 : static void
1503 : fd_guih_printf_ts_tile_timers( fd_guih_t * gui,
1504 : fd_guih_tile_timers_t const * prev,
1505 0 : fd_guih_tile_timers_t const * cur ) {
1506 0 : jsonp_open_object( gui->http, NULL );
1507 0 : jsonp_ulong_as_str( gui->http, "timestamp_nanos", 0 );
1508 0 : jsonp_open_array( gui->http, "tile_timers" );
1509 0 : fd_guih_printf_tile_timers( gui, prev, cur );
1510 0 : jsonp_close_array( gui->http );
1511 0 : jsonp_close_object( gui->http );
1512 0 : }
1513 :
1514 : void
1515 : fd_guih_printf_slot( fd_guih_t * gui,
1516 0 : ulong _slot ) {
1517 0 : fd_guih_slot_t * slot = fd_guih_get_slot( gui, _slot );
1518 :
1519 0 : char const * level;
1520 0 : switch( slot->level ) {
1521 0 : case FD_GUIH_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1522 0 : case FD_GUIH_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1523 0 : case FD_GUIH_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1524 0 : case FD_GUIH_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1525 0 : case FD_GUIH_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1526 0 : default: level = "unknown"; break;
1527 0 : }
1528 :
1529 0 : fd_guih_slot_t * parent_slot = fd_guih_get_slot( gui, slot->parent_slot );
1530 0 : long duration_nanos = LONG_MAX;
1531 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1532 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1533 0 : }
1534 :
1535 0 : jsonp_open_envelope( gui->http, "slot", "update" );
1536 0 : jsonp_open_object( gui->http, "value" );
1537 0 : fd_guih_leader_slot_t * lslot = fd_guih_get_leader_slot( gui, _slot );
1538 0 : jsonp_open_object( gui->http, "publish" );
1539 0 : jsonp_ulong( gui->http, "slot", _slot );
1540 0 : jsonp_bool( gui->http, "mine", slot->mine );
1541 0 : if( FD_UNLIKELY( slot->vote_slot!=ULONG_MAX ) ) jsonp_ulong( gui->http, "vote_slot", slot->vote_slot );
1542 0 : else jsonp_null( gui->http, "vote_slot" );
1543 0 : if( FD_UNLIKELY( slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, "vote_latency", slot->vote_latency );
1544 0 : else jsonp_null( gui->http, "vote_latency" );
1545 :
1546 0 : if( FD_UNLIKELY( lslot && lslot->leader_start_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
1547 0 : else jsonp_null ( gui->http, "start_timestamp_nanos" );
1548 0 : if( FD_UNLIKELY( lslot && lslot->leader_end_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "target_end_timestamp_nanos", lslot->leader_end_time );
1549 0 : else jsonp_null ( gui->http, "target_end_timestamp_nanos" );
1550 :
1551 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1552 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1553 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1554 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1555 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
1556 0 : jsonp_string( gui->http, "level", level );
1557 0 : if( FD_UNLIKELY( slot->nonvote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1558 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->nonvote_success );
1559 0 : if( FD_UNLIKELY( slot->nonvote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1560 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed );
1561 0 : if( FD_UNLIKELY( slot->vote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1562 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_success );
1563 0 : if( FD_UNLIKELY( slot->vote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1564 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->vote_failed );
1565 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1566 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1567 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1568 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1569 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
1570 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
1571 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1572 0 : else jsonp_ulong_as_str( gui->http, "transaction_fee", slot->transaction_fee );
1573 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1574 0 : else jsonp_ulong_as_str( gui->http, "priority_fee", slot->priority_fee );
1575 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1576 0 : else jsonp_ulong_as_str( gui->http, "tips", slot->tips );
1577 0 : jsonp_close_object( gui->http );
1578 0 : jsonp_close_object( gui->http );
1579 0 : jsonp_close_envelope( gui->http );
1580 0 : }
1581 :
1582 : void
1583 : fd_guih_printf_summary_ping( fd_guih_t * gui,
1584 0 : ulong id ) {
1585 0 : jsonp_open_envelope( gui->http, "summary", "ping" );
1586 0 : jsonp_ulong( gui->http, "id", id );
1587 0 : jsonp_null( gui->http, "value" );
1588 0 : jsonp_close_envelope( gui->http );
1589 0 : }
1590 :
1591 : void
1592 : fd_guih_printf_slot_rankings_request( fd_guih_t * gui,
1593 : ulong id,
1594 0 : int mine ) {
1595 0 : ulong epoch = ULONG_MAX;
1596 0 : for( ulong i = 0UL; i<2UL; i++ ) {
1597 0 : if( FD_LIKELY( gui->epoch.has_epoch[ i ] ) ) {
1598 : /* the "current" epoch is the smallest */
1599 0 : epoch = fd_ulong_min( epoch, gui->epoch.epochs[ i ].epoch );
1600 0 : }
1601 0 : }
1602 0 : ulong epoch_idx = epoch % 2UL;
1603 :
1604 0 : fd_guih_slot_rankings_t * rankings = fd_ptr_if( mine, (fd_guih_slot_rankings_t *)gui->epoch.epochs[ epoch_idx ].my_rankings, (fd_guih_slot_rankings_t *)gui->epoch.epochs[ epoch_idx ].rankings );
1605 :
1606 0 : jsonp_open_envelope( gui->http, "slot", "query_rankings" );
1607 0 : jsonp_ulong( gui->http, "id", id );
1608 0 : jsonp_open_object( gui->http, "value" );
1609 :
1610 0 : #define OUTPUT_RANKING_ARRAY(field) \
1611 0 : jsonp_open_array( gui->http, "slots_" FD_STRINGIFY(field) ); \
1612 0 : for( ulong i = 0UL; i<fd_ulong_if( epoch==ULONG_MAX, 0UL, FD_GUIH_SLOT_RANKINGS_SZ ); i++ ) { \
1613 0 : if( FD_UNLIKELY( rankings->field[ i ].slot==ULONG_MAX ) ) break; \
1614 0 : jsonp_ulong( gui->http, NULL, rankings->field[ i ].slot ); \
1615 0 : } \
1616 0 : jsonp_close_array( gui->http ); \
1617 0 : jsonp_open_array( gui->http, "vals_" FD_STRINGIFY(field) ); \
1618 0 : for( ulong i = 0UL; i<fd_ulong_if( epoch==ULONG_MAX, 0UL, FD_GUIH_SLOT_RANKINGS_SZ ); i++ ) { \
1619 0 : if( FD_UNLIKELY( rankings->field[ i ].slot==ULONG_MAX ) ) break; \
1620 0 : jsonp_ulong( gui->http, NULL, rankings->field[ i ].value ); \
1621 0 : } \
1622 0 : jsonp_close_array( gui->http )
1623 :
1624 0 : OUTPUT_RANKING_ARRAY( largest_tips );
1625 0 : OUTPUT_RANKING_ARRAY( largest_fees );
1626 0 : OUTPUT_RANKING_ARRAY( largest_rewards );
1627 0 : OUTPUT_RANKING_ARRAY( largest_rewards_per_cu );
1628 0 : OUTPUT_RANKING_ARRAY( largest_duration );
1629 0 : OUTPUT_RANKING_ARRAY( largest_compute_units );
1630 0 : OUTPUT_RANKING_ARRAY( largest_skipped );
1631 0 : OUTPUT_RANKING_ARRAY( smallest_tips );
1632 0 : OUTPUT_RANKING_ARRAY( smallest_fees );
1633 0 : OUTPUT_RANKING_ARRAY( smallest_rewards );
1634 0 : OUTPUT_RANKING_ARRAY( smallest_rewards_per_cu );
1635 0 : OUTPUT_RANKING_ARRAY( smallest_duration );
1636 0 : OUTPUT_RANKING_ARRAY( smallest_compute_units );
1637 0 : OUTPUT_RANKING_ARRAY( smallest_skipped );
1638 :
1639 0 : #undef OUTPUT_RANKING_ARRAY
1640 :
1641 0 : jsonp_close_object( gui->http );
1642 0 : jsonp_close_envelope( gui->http );
1643 0 : }
1644 :
1645 : void
1646 : fd_guih_printf_slot_request( fd_guih_t * gui,
1647 : ulong _slot,
1648 0 : ulong id ) {
1649 0 : fd_guih_slot_t * slot = fd_guih_get_slot( gui, _slot );
1650 :
1651 0 : char const * level;
1652 0 : switch( slot->level ) {
1653 0 : case FD_GUIH_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1654 0 : case FD_GUIH_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1655 0 : case FD_GUIH_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1656 0 : case FD_GUIH_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1657 0 : case FD_GUIH_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1658 0 : default: level = "unknown"; break;
1659 0 : }
1660 :
1661 0 : fd_guih_slot_t * parent_slot = fd_guih_get_slot( gui, slot->parent_slot );
1662 0 : long duration_nanos = LONG_MAX;
1663 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1664 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1665 0 : }
1666 :
1667 0 : jsonp_open_envelope( gui->http, "slot", "query" );
1668 0 : jsonp_ulong( gui->http, "id", id );
1669 0 : jsonp_open_object( gui->http, "value" );
1670 0 : fd_guih_leader_slot_t * lslot = fd_guih_get_leader_slot( gui, _slot );
1671 :
1672 0 : jsonp_open_object( gui->http, "publish" );
1673 0 : jsonp_ulong( gui->http, "slot", _slot );
1674 0 : jsonp_bool( gui->http, "mine", slot->mine );
1675 0 : if( FD_UNLIKELY( slot->vote_slot!=ULONG_MAX ) ) jsonp_ulong( gui->http, "vote_slot", slot->vote_slot );
1676 0 : else jsonp_null( gui->http, "vote_slot" );
1677 0 : if( FD_UNLIKELY( slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, "vote_latency", slot->vote_latency );
1678 0 : else jsonp_null( gui->http, "vote_latency" );
1679 :
1680 0 : if( FD_UNLIKELY( lslot && lslot->leader_start_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
1681 0 : else jsonp_null ( gui->http, "start_timestamp_nanos" );
1682 0 : if( FD_UNLIKELY( lslot && lslot->leader_end_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "target_end_timestamp_nanos", lslot->leader_end_time );
1683 0 : else jsonp_null ( gui->http, "target_end_timestamp_nanos" );
1684 :
1685 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1686 0 : jsonp_string( gui->http, "level", level );
1687 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1688 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1689 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1690 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
1691 0 : if( FD_UNLIKELY( slot->nonvote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1692 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->nonvote_success );
1693 0 : if( FD_UNLIKELY( slot->nonvote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1694 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed );
1695 0 : if( FD_UNLIKELY( slot->vote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1696 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_success );
1697 0 : if( FD_UNLIKELY( slot->vote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1698 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->vote_failed );
1699 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1700 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1701 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1702 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1703 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
1704 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
1705 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1706 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
1707 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1708 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
1709 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1710 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
1711 0 : jsonp_close_object( gui->http );
1712 :
1713 0 : jsonp_close_object( gui->http );
1714 0 : jsonp_close_envelope( gui->http );
1715 0 : }
1716 :
1717 : void
1718 : fd_guih_printf_slot_transactions_request( fd_guih_t * gui,
1719 : ulong _slot,
1720 0 : ulong id ) {
1721 0 : fd_guih_slot_t * slot = fd_guih_get_slot( gui, _slot );
1722 :
1723 0 : char const * level;
1724 0 : switch( slot->level ) {
1725 0 : case FD_GUIH_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1726 0 : case FD_GUIH_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1727 0 : case FD_GUIH_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1728 0 : case FD_GUIH_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1729 0 : case FD_GUIH_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1730 0 : default: level = "unknown"; break;
1731 0 : }
1732 :
1733 0 : fd_guih_slot_t * parent_slot = fd_guih_get_slot( gui, slot->parent_slot );
1734 0 : long duration_nanos = LONG_MAX;
1735 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1736 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1737 0 : }
1738 :
1739 0 : jsonp_open_envelope( gui->http, "slot", "query_transactions" );
1740 0 : jsonp_ulong( gui->http, "id", id );
1741 0 : jsonp_open_object( gui->http, "value" );
1742 0 : fd_guih_leader_slot_t * lslot = fd_guih_get_leader_slot( gui, _slot );
1743 :
1744 0 : jsonp_open_object( gui->http, "publish" );
1745 0 : jsonp_ulong( gui->http, "slot", _slot );
1746 0 : jsonp_bool( gui->http, "mine", slot->mine );
1747 0 : if( FD_UNLIKELY( slot->vote_slot!=ULONG_MAX ) ) jsonp_ulong( gui->http, "vote_slot", slot->vote_slot );
1748 0 : else jsonp_null( gui->http, "vote_slot" );
1749 0 : if( FD_UNLIKELY( slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, "vote_latency", slot->vote_latency );
1750 0 : else jsonp_null( gui->http, "vote_latency" );
1751 :
1752 0 : if( FD_UNLIKELY( lslot && lslot->leader_start_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
1753 0 : else jsonp_null ( gui->http, "start_timestamp_nanos" );
1754 0 : if( FD_UNLIKELY( lslot && lslot->leader_end_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "target_end_timestamp_nanos", lslot->leader_end_time );
1755 0 : else jsonp_null ( gui->http, "target_end_timestamp_nanos" );
1756 :
1757 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1758 0 : jsonp_string( gui->http, "level", level );
1759 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1760 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1761 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1762 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
1763 0 : if( FD_UNLIKELY( slot->nonvote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1764 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->nonvote_success );
1765 0 : if( FD_UNLIKELY( slot->nonvote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1766 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed );
1767 0 : if( FD_UNLIKELY( slot->vote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1768 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_success );
1769 0 : if( FD_UNLIKELY( slot->vote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1770 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->vote_failed );
1771 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1772 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1773 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1774 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1775 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
1776 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
1777 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1778 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
1779 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1780 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
1781 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1782 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
1783 0 : jsonp_close_object( gui->http );
1784 :
1785 0 : if( FD_UNLIKELY( lslot && lslot->unbecame_leader ) ) {
1786 0 : jsonp_open_object( gui->http, "limits" );
1787 0 : jsonp_ulong( gui->http, "used_total_block_cost", lslot->scheduler_stats->limits_usage->block_cost );
1788 0 : jsonp_ulong( gui->http, "used_total_vote_cost", lslot->scheduler_stats->limits_usage->vote_cost );
1789 0 : jsonp_ulong( gui->http, "used_total_bytes", lslot->scheduler_stats->limits_usage->block_data_bytes );
1790 0 : jsonp_ulong( gui->http, "used_total_microblocks", lslot->scheduler_stats->limits_usage->microblocks );
1791 0 : jsonp_open_array( gui->http, "used_account_write_costs" );
1792 0 : for( ulong i = 0; i<FD_PACK_TOP_WRITERS_CNT; i++ ) {
1793 0 : if( FD_UNLIKELY( !memcmp( lslot->scheduler_stats->limits_usage->top_writers[ i ].key.b, ((fd_pubkey_t){ 0 }).uc, sizeof(fd_pubkey_t) ) ) ) break;
1794 :
1795 0 : jsonp_open_object( gui->http, NULL );
1796 0 : char account_base58[ FD_BASE58_ENCODED_32_SZ ];
1797 0 : fd_base58_encode_32( lslot->scheduler_stats->limits_usage->top_writers[ i ].key.b, NULL, account_base58 );
1798 0 : jsonp_string( gui->http, "account", account_base58 );
1799 0 : jsonp_ulong( gui->http, "cost", lslot->scheduler_stats->limits_usage->top_writers[ i ].total_cost );
1800 0 : jsonp_close_object( gui->http );
1801 0 : }
1802 0 : jsonp_close_array( gui->http );
1803 :
1804 0 : jsonp_ulong( gui->http, "max_total_block_cost", lslot->scheduler_stats->limits->max_cost_per_block );
1805 0 : jsonp_ulong( gui->http, "max_total_vote_cost", lslot->scheduler_stats->limits->max_vote_cost_per_block );
1806 0 : jsonp_ulong( gui->http, "max_account_write_cost", lslot->scheduler_stats->limits->max_write_cost_per_acct );
1807 0 : jsonp_ulong( gui->http, "max_total_bytes", lslot->scheduler_stats->limits->max_data_bytes_per_block );
1808 0 : jsonp_ulong( gui->http, "max_total_microblocks", lslot->max_microblocks );
1809 0 : jsonp_close_object( gui->http );
1810 :
1811 0 : jsonp_open_object( gui->http, "scheduler_stats" );
1812 0 : char block_hash_base58[ FD_BASE58_ENCODED_32_SZ ];
1813 0 : fd_base58_encode_32( lslot->block_hash.uc, NULL, block_hash_base58 );
1814 0 : jsonp_string( gui->http, "block_hash", block_hash_base58 );
1815 :
1816 0 : switch( lslot->scheduler_stats->end_slot_reason ) {
1817 0 : case FD_PACK_END_SLOT_REASON_TIME: {
1818 0 : jsonp_string( gui->http, "end_slot_reason", "timeout" );
1819 0 : break;
1820 0 : }
1821 0 : case FD_PACK_END_SLOT_REASON_MICROBLOCK: {
1822 0 : jsonp_string( gui->http, "end_slot_reason", "microblock_limit" );
1823 0 : break;
1824 0 : }
1825 0 : case FD_PACK_END_SLOT_REASON_LEADER_SWITCH: {
1826 0 : jsonp_string( gui->http, "end_slot_reason", "leader_switch" );
1827 0 : break;
1828 0 : }
1829 0 : default: FD_LOG_ERR(( "unreachable" ));
1830 0 : }
1831 0 : jsonp_open_array( gui->http, "slot_schedule_counts" );
1832 0 : for( ulong i = 0; i<FD_METRICS_COUNTER_PACK_TXN_SCHEDULED_CNT; i++ ) jsonp_ulong( gui->http, NULL, lslot->scheduler_stats->block_results[ i ] );
1833 0 : jsonp_close_array( gui->http );
1834 0 : jsonp_open_array( gui->http, "end_slot_schedule_counts" );
1835 0 : for( ulong i = 0; i<FD_METRICS_COUNTER_PACK_TXN_SCHEDULED_CNT; i++ ) jsonp_ulong( gui->http, NULL, lslot->scheduler_stats->end_block_results[ i ] );
1836 0 : jsonp_close_array( gui->http );
1837 :
1838 0 : if( FD_LIKELY( lslot->scheduler_stats->pending_smallest->cus!=ULONG_MAX ) ) jsonp_ulong( gui->http, "pending_smallest_cost", lslot->scheduler_stats->pending_smallest->cus );
1839 0 : else jsonp_null( gui->http, "pending_smallest_cost" );
1840 0 : if( FD_LIKELY( lslot->scheduler_stats->pending_smallest->bytes!=ULONG_MAX ) ) jsonp_ulong( gui->http, "pending_smallest_bytes", lslot->scheduler_stats->pending_smallest->bytes );
1841 0 : else jsonp_null( gui->http, "pending_smallest_bytes" );
1842 0 : if( FD_LIKELY( lslot->scheduler_stats->pending_votes_smallest->cus!=ULONG_MAX ) ) jsonp_ulong( gui->http, "pending_vote_smallest_cost", lslot->scheduler_stats->pending_votes_smallest->cus );
1843 0 : else jsonp_null( gui->http, "pending_vote_smallest_cost" );
1844 0 : if( FD_LIKELY( lslot->scheduler_stats->pending_votes_smallest->bytes!=ULONG_MAX ) ) jsonp_ulong( gui->http, "pending_vote_smallest_bytes", lslot->scheduler_stats->pending_votes_smallest->bytes );
1845 0 : else jsonp_null( gui->http, "pending_vote_smallest_bytes" );
1846 0 : jsonp_close_object( gui->http );
1847 :
1848 0 : } else {
1849 0 : jsonp_null( gui->http, "limits" );
1850 0 : jsonp_null( gui->http, "scheduler_stats" );
1851 0 : }
1852 :
1853 0 : int overwritten = lslot && (gui->pack_txn_idx - lslot->txs.start_offset)>FD_GUIH_TXN_HISTORY_SZ;
1854 0 : int processed_all_microblocks = lslot && lslot->unbecame_leader &&
1855 0 : lslot->txs.start_offset!=ULONG_MAX &&
1856 0 : lslot->txs.end_offset!=ULONG_MAX &&
1857 0 : lslot->txs.microblocks_upper_bound!=UINT_MAX &&
1858 0 : lslot->txs.begin_microblocks==lslot->txs.end_microblocks &&
1859 0 : lslot->txs.begin_microblocks==lslot->txs.microblocks_upper_bound;
1860 :
1861 0 : if( FD_LIKELY( !overwritten && processed_all_microblocks ) ) {
1862 0 : ulong txn_cnt = lslot->txs.end_offset-lslot->txs.start_offset;
1863 :
1864 0 : jsonp_open_object( gui->http, "transactions" );
1865 0 : jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
1866 0 : jsonp_long_as_str( gui->http, "target_end_timestamp_nanos", lslot->leader_end_time );
1867 0 : jsonp_open_array( gui->http, "txn_mb_start_timestamps_nanos" );
1868 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + (long)gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->microblock_start_ns_dt );
1869 0 : jsonp_close_array( gui->http );
1870 0 : jsonp_open_array( gui->http, "txn_mb_end_timestamps_nanos" );
1871 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1872 0 : long const clamped_microblock_end_ns_dt = fd_long_max( (long)gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->microblock_end_ns_dt, (long)gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->microblock_start_ns_dt + 1L );
1873 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + clamped_microblock_end_ns_dt );
1874 0 : }
1875 0 : jsonp_close_array( gui->http );
1876 0 : jsonp_open_array( gui->http, "txn_compute_units_requested" );
1877 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->compute_units_requested );
1878 0 : jsonp_close_array( gui->http );
1879 0 : jsonp_open_array( gui->http, "txn_compute_units_consumed" );
1880 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->compute_units_consumed );
1881 0 : jsonp_close_array( gui->http );
1882 0 : jsonp_open_array( gui->http, "txn_priority_fee" );
1883 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong_as_str( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->priority_fee );
1884 0 : jsonp_close_array( gui->http );
1885 0 : jsonp_open_array( gui->http, "txn_transaction_fee" );
1886 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong_as_str( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->transaction_fee );
1887 0 : jsonp_close_array( gui->http );
1888 0 : jsonp_open_array( gui->http, "txn_error_code" );
1889 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->error_code );
1890 0 : jsonp_close_array( gui->http );
1891 0 : jsonp_open_array( gui->http, "txn_from_bundle" );
1892 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_bool( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->flags & FD_GUIH_TXN_FLAGS_FROM_BUNDLE );
1893 0 : jsonp_close_array( gui->http );
1894 0 : jsonp_open_array( gui->http, "txn_is_simple_vote" );
1895 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_bool( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->flags & FD_GUIH_TXN_FLAGS_IS_SIMPLE_VOTE );
1896 0 : jsonp_close_array( gui->http );
1897 0 : jsonp_open_array( gui->http, "txn_bank_idx" );
1898 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->bank_idx );
1899 0 : jsonp_close_array( gui->http );
1900 0 : jsonp_open_array( gui->http, "txn_check_start_timestamps_nanos" );
1901 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1902 0 : fd_guih_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ];
1903 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + (long)txn->microblock_start_ns_dt + (long)txn->txn_ns_dt.check_start );
1904 0 : }
1905 0 : jsonp_close_array( gui->http );
1906 0 : jsonp_open_array( gui->http, "txn_load_start_timestamps_nanos" );
1907 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1908 0 : fd_guih_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ];
1909 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + (long)txn->microblock_start_ns_dt + (long)txn->txn_ns_dt.load_start );
1910 0 : }
1911 0 : jsonp_close_array( gui->http );
1912 0 : jsonp_open_array( gui->http, "txn_execute_start_timestamps_nanos" );
1913 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1914 0 : fd_guih_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ];
1915 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + (long)txn->microblock_start_ns_dt + (long)txn->txn_ns_dt.exec_start );
1916 0 : }
1917 0 : jsonp_close_array( gui->http );
1918 0 : jsonp_open_array( gui->http, "txn_commit_start_timestamps_nanos" );
1919 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1920 0 : fd_guih_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ];
1921 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + (long)txn->microblock_start_ns_dt + (long)txn->txn_ns_dt.commit_start );
1922 0 : }
1923 0 : jsonp_close_array( gui->http );
1924 0 : jsonp_open_array( gui->http, "txn_commit_end_timestamps_nanos" );
1925 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1926 0 : fd_guih_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ];
1927 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + (long)txn->microblock_start_ns_dt + (long)txn->txn_ns_dt.commit_end );
1928 0 : }
1929 0 : jsonp_close_array( gui->http );
1930 0 : jsonp_open_array( gui->http, "txn_arrival_timestamps_nanos" );
1931 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_long_as_str( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->timestamp_arrival_nanos );
1932 0 : jsonp_close_array( gui->http );
1933 0 : jsonp_open_array( gui->http, "txn_tips" );
1934 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong_as_str( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->tips );
1935 0 : jsonp_close_array( gui->http );
1936 0 : jsonp_open_array( gui->http, "txn_source_ipv4" );
1937 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1938 0 : char addr[ 64 ];
1939 0 : fd_cstr_printf_check( addr, sizeof(addr), NULL, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->source_ipv4 ) );
1940 0 : jsonp_string( gui->http, NULL, addr );
1941 0 : }
1942 0 : jsonp_close_array( gui->http );
1943 0 : jsonp_open_array( gui->http, "txn_source_tpu" );
1944 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1945 0 : switch ( gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->source_tpu ) {
1946 0 : case FD_TXN_M_TPU_SOURCE_QUIC: {
1947 0 : jsonp_string( gui->http, NULL, "quic");
1948 0 : break;
1949 0 : }
1950 0 : case FD_TXN_M_TPU_SOURCE_UDP : {
1951 0 : jsonp_string( gui->http, NULL, "udp");
1952 0 : break;
1953 0 : }
1954 0 : case FD_TXN_M_TPU_SOURCE_GOSSIP: {
1955 0 : jsonp_string( gui->http, NULL, "gossip");
1956 0 : break;
1957 0 : }
1958 0 : case FD_TXN_M_TPU_SOURCE_BUNDLE: {
1959 0 : jsonp_string( gui->http, NULL, "bundle");
1960 0 : break;
1961 0 : }
1962 0 : case FD_TXN_M_TPU_SOURCE_TXSEND: {
1963 0 : jsonp_string( gui->http, NULL, "send");
1964 0 : break;
1965 0 : }
1966 0 : default: FD_LOG_ERR(("unknown tpu"));
1967 0 : }
1968 0 : }
1969 0 : jsonp_close_array( gui->http );
1970 0 : jsonp_open_array( gui->http, "txn_microblock_id" );
1971 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->microblock_idx );
1972 0 : jsonp_close_array( gui->http );
1973 0 : jsonp_open_array( gui->http, "txn_landed" );
1974 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_bool( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->flags & FD_GUIH_TXN_FLAGS_LANDED_IN_BLOCK );
1975 0 : jsonp_close_array( gui->http );
1976 0 : jsonp_open_array( gui->http, "txn_signature" );
1977 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1978 0 : FD_BASE58_ENCODE_64_BYTES( gui->txs[ (lslot->txs.start_offset + i)%FD_GUIH_TXN_HISTORY_SZ ]->signature, encoded_signature );
1979 0 : jsonp_string( gui->http, NULL, encoded_signature );
1980 0 : }
1981 0 : jsonp_close_array( gui->http );
1982 0 : jsonp_close_object( gui->http );
1983 0 : } else {
1984 0 : jsonp_null( gui->http, "transactions" );
1985 0 : }
1986 :
1987 0 : jsonp_close_object( gui->http );
1988 0 : jsonp_close_envelope( gui->http );
1989 0 : }
1990 :
1991 : void
1992 : fd_guih_printf_slot_request_detailed( fd_guih_t * gui,
1993 : ulong _slot,
1994 0 : ulong id ) {
1995 0 : fd_guih_slot_t * slot = fd_guih_get_slot( gui, _slot );
1996 :
1997 0 : char const * level;
1998 0 : switch( slot->level ) {
1999 0 : case FD_GUIH_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
2000 0 : case FD_GUIH_SLOT_LEVEL_COMPLETED: level = "completed"; break;
2001 0 : case FD_GUIH_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
2002 0 : case FD_GUIH_SLOT_LEVEL_ROOTED: level = "rooted"; break;
2003 0 : case FD_GUIH_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
2004 0 : default: level = "unknown"; break;
2005 0 : }
2006 :
2007 0 : fd_guih_slot_t * parent_slot = fd_guih_get_slot( gui, slot->parent_slot );
2008 0 : long duration_nanos = LONG_MAX;
2009 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
2010 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
2011 0 : }
2012 :
2013 0 : jsonp_open_envelope( gui->http, "slot", "query_detailed" );
2014 0 : jsonp_ulong( gui->http, "id", id );
2015 0 : jsonp_open_object( gui->http, "value" );
2016 0 : fd_guih_leader_slot_t * lslot = fd_guih_get_leader_slot( gui, _slot );
2017 :
2018 0 : jsonp_open_object( gui->http, "publish" );
2019 0 : jsonp_ulong( gui->http, "slot", _slot );
2020 0 : jsonp_bool( gui->http, "mine", slot->mine );
2021 0 : if( FD_UNLIKELY( slot->vote_slot!=ULONG_MAX ) ) jsonp_ulong( gui->http, "vote_slot", slot->vote_slot );
2022 0 : else jsonp_null( gui->http, "vote_slot" );
2023 0 : if( FD_UNLIKELY( slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, "vote_latency", slot->vote_latency );
2024 0 : else jsonp_null( gui->http, "vote_latency" );
2025 :
2026 0 : if( FD_UNLIKELY( lslot && lslot->leader_start_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
2027 0 : else jsonp_null ( gui->http, "start_timestamp_nanos" );
2028 0 : if( FD_UNLIKELY( lslot && lslot->leader_end_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "target_end_timestamp_nanos", lslot->leader_end_time );
2029 0 : else jsonp_null ( gui->http, "target_end_timestamp_nanos" );
2030 :
2031 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
2032 0 : jsonp_string( gui->http, "level", level );
2033 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
2034 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
2035 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
2036 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
2037 0 : if( FD_UNLIKELY( slot->nonvote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
2038 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->nonvote_success );
2039 0 : if( FD_UNLIKELY( slot->nonvote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
2040 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed );
2041 0 : if( FD_UNLIKELY( slot->vote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
2042 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_success );
2043 0 : if( FD_UNLIKELY( slot->vote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
2044 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->vote_failed );
2045 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
2046 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
2047 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
2048 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
2049 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
2050 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
2051 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
2052 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
2053 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
2054 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
2055 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
2056 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
2057 0 : jsonp_close_object( gui->http );
2058 :
2059 0 : if( FD_LIKELY( gui->summary.slot_completed!=ULONG_MAX && gui->summary.slot_completed>_slot ) ) {
2060 0 : fd_guih_printf_waterfall( gui, slot->waterfall_begin, slot->waterfall_end );
2061 :
2062 0 : fd_guih_leader_slot_t * lslot = fd_guih_get_leader_slot( gui, _slot );
2063 0 : if( FD_LIKELY( lslot && lslot->unbecame_leader ) ) {
2064 0 : jsonp_open_array( gui->http, "tile_timers" );
2065 0 : fd_guih_tile_timers_t const * prev_timer = lslot->tile_timers;
2066 0 : for( ulong i=1UL; i<lslot->tile_timers_sample_cnt; i++ ) {
2067 0 : fd_guih_tile_timers_t const * cur_timer = lslot->tile_timers + i * gui->tile_cnt;
2068 0 : fd_guih_printf_ts_tile_timers( gui, prev_timer, cur_timer );
2069 0 : prev_timer = cur_timer;
2070 0 : }
2071 0 : jsonp_close_array( gui->http );
2072 0 : } else {
2073 : /* Our tile timers were overwritten. */
2074 0 : jsonp_null( gui->http, "tile_timers" );
2075 0 : }
2076 :
2077 0 : if( FD_LIKELY( lslot && lslot->unbecame_leader ) ) {
2078 0 : jsonp_open_array( gui->http, "scheduler_counts" );
2079 : /* Unlike tile timers (which are counters), scheduler counts
2080 : are a gauge and we don't take a diff. */
2081 0 : for( ulong i=0UL; i<lslot->scheduler_counts_sample_cnt; i++ ) {
2082 0 : fd_guih_scheduler_counts_t const * cur = lslot->scheduler_counts[ i ];
2083 0 : jsonp_open_object( gui->http, NULL );
2084 0 : jsonp_long_as_str( gui->http, "timestamp_nanos", cur->sample_time_ns );
2085 0 : jsonp_ulong ( gui->http, "regular", cur->regular );
2086 0 : jsonp_ulong ( gui->http, "votes", cur->votes );
2087 0 : jsonp_ulong ( gui->http, "conflicting", cur->conflicting );
2088 0 : jsonp_ulong ( gui->http, "bundles", cur->bundles );
2089 0 : jsonp_close_object( gui->http );
2090 0 : }
2091 0 : jsonp_close_array( gui->http );
2092 0 : } else {
2093 : /* Our scheduler counts were overwritten. */
2094 0 : jsonp_null( gui->http, "scheduler_counts" );
2095 0 : }
2096 :
2097 0 : fd_guih_printf_tile_stats( gui, slot->tile_stats_begin, slot->tile_stats_end );
2098 0 : } else {
2099 0 : jsonp_null( gui->http, "waterfall" );
2100 0 : jsonp_null( gui->http, "tile_timers" );
2101 0 : jsonp_null( gui->http, "tile_primary_metric" );
2102 0 : }
2103 :
2104 0 : jsonp_close_object( gui->http );
2105 0 : jsonp_close_envelope( gui->http );
2106 0 : }
2107 :
2108 : void
2109 0 : fd_guih_printf_shreds_staged( fd_guih_t * gui, ulong start_offset, ulong end_offset ) {
2110 0 : ulong min_slot = ULONG_MAX;
2111 0 : long min_ts = LONG_MAX;
2112 :
2113 0 : for( ulong i=start_offset; i<end_offset; i++ ) {
2114 0 : min_slot = fd_ulong_min( min_slot, gui->shreds.staged[ i % FD_GUIH_SHREDS_STAGING_SZ ].slot );
2115 0 : min_ts = fd_long_min ( min_ts, gui->shreds.staged[ i % FD_GUIH_SHREDS_STAGING_SZ ].timestamp );
2116 0 : }
2117 :
2118 0 : jsonp_ulong ( gui->http, "reference_slot", min_slot );
2119 0 : jsonp_long_as_str( gui->http, "reference_ts", min_ts );
2120 :
2121 0 : jsonp_open_array( gui->http, "slot_delta" );
2122 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_ulong( gui->http, NULL, gui->shreds.staged[ i % FD_GUIH_SHREDS_STAGING_SZ ].slot-min_slot );
2123 0 : jsonp_close_array( gui->http );
2124 0 : jsonp_open_array( gui->http, "shred_idx" );
2125 0 : for( ulong i=start_offset; i<end_offset; i++ ) {
2126 0 : if( FD_LIKELY( gui->shreds.staged[ i % FD_GUIH_SHREDS_STAGING_SZ ].shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, gui->shreds.staged[ i % FD_GUIH_SHREDS_STAGING_SZ ].shred_idx );
2127 0 : else jsonp_null ( gui->http, NULL );
2128 0 : }
2129 0 : jsonp_close_array( gui->http );
2130 0 : jsonp_open_array( gui->http, "event" );
2131 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_ulong( gui->http, NULL, gui->shreds.staged[ i % FD_GUIH_SHREDS_STAGING_SZ ].event );
2132 0 : jsonp_close_array( gui->http );
2133 0 : jsonp_open_array( gui->http, "event_ts_delta" );
2134 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_long_as_str( gui->http, NULL, gui->shreds.staged[ i % FD_GUIH_SHREDS_STAGING_SZ ].timestamp-min_ts );
2135 0 : jsonp_close_array( gui->http );
2136 0 : }
2137 :
2138 : void
2139 0 : fd_guih_printf_shreds_history( fd_guih_t * gui, ulong _slot ) {
2140 0 : fd_guih_slot_t * slot = fd_guih_get_slot( gui, _slot );
2141 0 : FD_TEST( slot );
2142 0 : ulong end_offset = slot->shreds.end_offset;
2143 0 : ulong start_offset = slot->shreds.start_offset;
2144 0 : FD_TEST( slot->shreds.end_offset + FD_GUIH_SHREDS_HISTORY_SZ > gui->shreds.history_tail );
2145 :
2146 0 : long min_ts = LONG_MAX;
2147 0 : for( ulong i=start_offset; i<end_offset; i++ ) {
2148 0 : min_ts = fd_long_min ( min_ts, gui->shreds.history[ i % FD_GUIH_SHREDS_HISTORY_SZ ].timestamp );
2149 0 : }
2150 :
2151 0 : jsonp_ulong ( gui->http, "reference_slot", _slot );
2152 0 : jsonp_long_as_str( gui->http, "reference_ts", min_ts );
2153 :
2154 0 : jsonp_open_array( gui->http, "slot_delta" );
2155 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_ulong( gui->http, NULL, 0UL );
2156 0 : jsonp_close_array( gui->http );
2157 0 : jsonp_open_array( gui->http, "shred_idx" );
2158 0 : for( ulong i=start_offset; i<end_offset; i++ ) {
2159 0 : if( FD_LIKELY( gui->shreds.history[ i % FD_GUIH_SHREDS_HISTORY_SZ ].shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, gui->shreds.history[ i % FD_GUIH_SHREDS_HISTORY_SZ ].shred_idx );
2160 0 : else jsonp_null ( gui->http, NULL );
2161 0 : }
2162 0 : jsonp_close_array( gui->http );
2163 0 : jsonp_open_array( gui->http, "event" );
2164 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_ulong( gui->http, NULL, gui->shreds.history[ i % FD_GUIH_SHREDS_HISTORY_SZ ].event );
2165 0 : jsonp_close_array( gui->http );
2166 0 : jsonp_open_array( gui->http, "event_ts_delta" );
2167 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_long_as_str( gui->http, NULL, gui->shreds.history[ i % FD_GUIH_SHREDS_HISTORY_SZ ].timestamp-min_ts );
2168 0 : jsonp_close_array( gui->http );
2169 0 : }
2170 :
2171 :
2172 :
2173 : void
2174 0 : fd_guih_printf_shred_rebroadcast( fd_guih_t * gui, long after ) {
2175 0 : FD_TEST( gui->shreds.staged_next_broadcast!=ULONG_MAX );
2176 :
2177 0 : ulong _start_offset = gui->shreds.staged_next_broadcast;
2178 0 : for( ulong i=gui->shreds.staged_head; i<gui->shreds.staged_next_broadcast; i++ ) {
2179 0 : if( FD_LIKELY( gui->shreds.staged[ i % FD_GUIH_SHREDS_STAGING_SZ ].timestamp<after ) ) continue;
2180 0 : _start_offset = i;
2181 0 : break;
2182 0 : }
2183 :
2184 0 : jsonp_open_envelope( gui->http, "slot", "live_shreds" );
2185 0 : jsonp_open_object( gui->http, "value" );
2186 0 : fd_guih_printf_shreds_staged( gui, _start_offset, gui->shreds.staged_next_broadcast );
2187 0 : jsonp_close_object( gui->http );
2188 0 : jsonp_close_envelope( gui->http );
2189 0 : }
2190 :
2191 : void
2192 : fd_guih_printf_slot_query_shreds( fd_guih_t * gui,
2193 : ulong _slot,
2194 0 : ulong id ) {
2195 0 : jsonp_open_envelope( gui->http, "slot", "query_shreds" );
2196 0 : jsonp_ulong( gui->http, "id", id );
2197 0 : jsonp_open_object( gui->http, "value" );
2198 0 : fd_guih_printf_shreds_history( gui, _slot );
2199 0 : jsonp_close_object( gui->http );
2200 0 : jsonp_close_envelope( gui->http );
2201 0 : }
|