Line data Source code
1 : #include "fd_gui_printf.h"
2 : #include "fd_gui_config_parse.h"
3 :
4 : #include "../../waltz/http/fd_http_server_private.h"
5 : #include "../../ballet/utf8/fd_utf8.h"
6 : #include "../../disco/fd_txn_m.h"
7 : #include "../../disco/metrics/fd_metrics.h"
8 :
9 : #ifdef __has_include
10 : #if __has_include("../../app/fdctl/version.h")
11 : #include "../../app/fdctl/version.h"
12 : #endif
13 : #endif
14 :
15 : #ifndef FDCTL_COMMIT_REF_CSTR
16 : #define FDCTL_COMMIT_REF_CSTR "0000000000000000000000000000000000000000"
17 : #endif
18 :
19 : static void
20 0 : jsonp_strip_trailing_comma( fd_http_server_t * http ) {
21 0 : if( FD_LIKELY( !http->stage_err &&
22 0 : http->stage_len>=1UL &&
23 0 : http->oring[ (http->stage_off%http->oring_sz)+http->stage_len-1UL ]==(uchar)',' ) ) {
24 0 : http->stage_len--;
25 0 : }
26 0 : }
27 :
28 : static void
29 : jsonp_open_object( fd_http_server_t * http,
30 0 : char const * key ) {
31 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":{", key );
32 0 : else fd_http_server_printf( http, "{" );
33 0 : }
34 :
35 : static void
36 0 : jsonp_close_object( fd_http_server_t * http ) {
37 0 : jsonp_strip_trailing_comma( http );
38 0 : fd_http_server_printf( http, "}," );
39 0 : }
40 :
41 : static void
42 : jsonp_open_array( fd_http_server_t * http,
43 0 : char const * key ) {
44 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":[", key );
45 0 : else fd_http_server_printf( http, "[" );
46 0 : }
47 :
48 : static void
49 0 : jsonp_close_array( fd_http_server_t * http ) {
50 0 : jsonp_strip_trailing_comma( http );
51 0 : fd_http_server_printf( http, "]," );
52 0 : }
53 :
54 : static void
55 : jsonp_ulong( fd_http_server_t * http,
56 : char const * key,
57 0 : ulong value ) {
58 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%lu,", key, value );
59 0 : else fd_http_server_printf( http, "%lu,", value );
60 0 : }
61 :
62 : static void
63 : jsonp_long( fd_http_server_t * http,
64 : char const * key,
65 0 : long value ) {
66 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%ld,", key, value );
67 0 : else fd_http_server_printf( http, "%ld,", value );
68 0 : }
69 :
70 : static void
71 : jsonp_double( fd_http_server_t * http,
72 : char const * key,
73 0 : double value ) {
74 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%.2f,", key, value );
75 0 : else fd_http_server_printf( http, "%.2f,", value );
76 0 : }
77 :
78 : static void
79 : jsonp_ulong_as_str( fd_http_server_t * http,
80 : char const * key,
81 0 : ulong value ) {
82 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":\"%lu\",", key, value );
83 0 : else fd_http_server_printf( http, "\"%lu\",", value );
84 0 : }
85 :
86 : static void
87 : jsonp_long_as_str( fd_http_server_t * http,
88 : char const * key,
89 0 : long value ) {
90 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":\"%ld\",", key, value );
91 0 : else fd_http_server_printf( http, "\"%ld\",", value );
92 0 : }
93 :
94 : static void
95 : jsonp_sanitize_str( fd_http_server_t * http,
96 0 : ulong start_len ) {
97 : /* escape quotemark, reverse solidus, and control chars U+0000 through U+001F
98 : just replace with a space */
99 0 : uchar * data = http->oring;
100 0 : for( ulong i=start_len; i<http->stage_len; i++ ) {
101 0 : if( FD_UNLIKELY( data[ (http->stage_off%http->oring_sz)+i ] < 0x20 ||
102 0 : data[ (http->stage_off%http->oring_sz)+i ] == '"' ||
103 0 : data[ (http->stage_off%http->oring_sz)+i ] == '\\' ) ) {
104 0 : data[ (http->stage_off%http->oring_sz)+i ] = ' ';
105 0 : }
106 0 : }
107 0 : }
108 :
109 : static void
110 : jsonp_string( fd_http_server_t * http,
111 : char const * key,
112 0 : char const * value ) {
113 0 : char * val = (void *)value;
114 0 : if( FD_LIKELY( value ) ) {
115 0 : if( FD_UNLIKELY( !fd_utf8_verify( value, strlen( value ) ) )) {
116 0 : val = NULL;
117 0 : }
118 0 : }
119 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":", key );
120 0 : if( FD_LIKELY( val ) ) {
121 0 : fd_http_server_printf( http, "\"" );
122 0 : ulong start_len = http->stage_len;
123 0 : fd_http_server_printf( http, "%s", val );
124 0 : jsonp_sanitize_str( http, start_len );
125 0 : fd_http_server_printf( http, "\"," );
126 0 : } else {
127 0 : fd_http_server_printf( http, "null," );
128 0 : }
129 0 : }
130 :
131 : static void
132 : jsonp_bool( fd_http_server_t * http,
133 : char const * key,
134 0 : int value ) {
135 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%s,", key, value ? "true" : "false" );
136 0 : else fd_http_server_printf( http, "%s,", value ? "true" : "false" );
137 0 : }
138 :
139 : static void
140 : jsonp_null( fd_http_server_t * http,
141 0 : char const * key ) {
142 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\": null,", key );
143 0 : else fd_http_server_printf( http, "null," );
144 0 : }
145 :
146 : static void
147 : jsonp_open_envelope( fd_http_server_t * http,
148 : char const * topic,
149 0 : char const * key ) {
150 0 : jsonp_open_object( http, NULL );
151 0 : jsonp_string( http, "topic", topic );
152 0 : jsonp_string( http, "key", key );
153 0 : }
154 :
155 : static void
156 0 : jsonp_close_envelope( fd_http_server_t * http ) {
157 0 : jsonp_close_object( http );
158 0 : jsonp_strip_trailing_comma( http );
159 0 : }
160 :
161 : void
162 : fd_gui_printf_open_query_response_envelope( fd_http_server_t * http,
163 : char const * topic,
164 : char const * key,
165 0 : ulong id ) {
166 0 : jsonp_open_object( http, NULL );
167 0 : jsonp_string( http, "topic", topic );
168 0 : jsonp_string( http, "key", key );
169 0 : jsonp_ulong( http, "id", id );
170 0 : }
171 :
172 : void
173 0 : fd_gui_printf_close_query_response_envelope( fd_http_server_t * http ) {
174 0 : jsonp_close_object( http );
175 0 : jsonp_strip_trailing_comma( http );
176 0 : }
177 :
178 : void
179 : fd_gui_printf_null_query_response( fd_http_server_t * http,
180 : char const * topic,
181 : char const * key,
182 0 : ulong id ) {
183 0 : fd_gui_printf_open_query_response_envelope( http, topic, key, id );
184 0 : jsonp_null( http, "value" );
185 0 : fd_gui_printf_close_query_response_envelope( http );
186 0 : }
187 :
188 : void
189 0 : fd_gui_printf_version( fd_gui_t * gui ) {
190 0 : jsonp_open_envelope( gui->http, "summary", "version" );
191 0 : jsonp_string( gui->http, "value", gui->summary.version );
192 0 : jsonp_close_envelope( gui->http );
193 0 : }
194 :
195 : void
196 0 : fd_gui_printf_cluster( fd_gui_t * gui ) {
197 0 : jsonp_open_envelope( gui->http, "summary", "cluster" );
198 0 : jsonp_string( gui->http, "value", gui->summary.cluster );
199 0 : jsonp_close_envelope( gui->http );
200 0 : }
201 :
202 : void
203 0 : fd_gui_printf_commit_hash( fd_gui_t * gui ) {
204 0 : jsonp_open_envelope( gui->http, "summary", "commit_hash" );
205 0 : jsonp_string( gui->http, "value", FDCTL_COMMIT_REF_CSTR );
206 0 : jsonp_close_envelope( gui->http );
207 0 : }
208 :
209 : void
210 0 : fd_gui_printf_identity_key( fd_gui_t * gui ) {
211 0 : jsonp_open_envelope( gui->http, "summary", "identity_key" );
212 0 : jsonp_string( gui->http, "value", gui->summary.identity_key_base58 );
213 0 : jsonp_close_envelope( gui->http );
214 0 : }
215 :
216 : void
217 0 : fd_gui_printf_vote_key( fd_gui_t * gui ) {
218 0 : jsonp_open_envelope( gui->http, "summary", "vote_key" );
219 0 : if( FD_LIKELY( gui->summary.has_vote_key ) ) jsonp_string( gui->http, "value", gui->summary.vote_key_base58 );
220 0 : else jsonp_null( gui->http, "value" );
221 0 : jsonp_close_envelope( gui->http );
222 0 : }
223 :
224 : void
225 0 : fd_gui_printf_startup_time_nanos( fd_gui_t * gui ) {
226 0 : jsonp_open_envelope( gui->http, "summary", "startup_time_nanos" );
227 0 : jsonp_long_as_str( gui->http, "value", gui->summary.startup_time_nanos );
228 0 : jsonp_close_envelope( gui->http );
229 0 : }
230 :
231 : void
232 0 : fd_gui_printf_server_time_nanos( fd_gui_t * gui, long now ) {
233 0 : jsonp_open_envelope( gui->http, "summary", "server_time_nanos" );
234 0 : jsonp_long_as_str( gui->http, "value", now );
235 0 : jsonp_close_envelope( gui->http );
236 0 : }
237 :
238 : void
239 0 : fd_gui_printf_vote_distance( fd_gui_t * gui ) {
240 0 : jsonp_open_envelope( gui->http, "summary", "vote_distance" );
241 0 : jsonp_ulong( gui->http, "value", gui->summary.vote_distance );
242 0 : jsonp_close_envelope( gui->http );
243 0 : }
244 :
245 : void
246 0 : fd_gui_printf_repair_slot( fd_gui_t * gui ) {
247 0 : jsonp_open_envelope( gui->http, "summary", "repair_slot" );
248 0 : if( FD_LIKELY( gui->summary.slot_repair!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_repair );
249 0 : else jsonp_null ( gui->http, "value" );
250 0 : jsonp_close_envelope( gui->http );
251 0 : }
252 :
253 : void
254 0 : fd_gui_peers_printf_vote_slot( fd_gui_peers_ctx_t * peers ) {
255 0 : jsonp_open_envelope( peers->http, "summary", "vote_slot" );
256 0 : if( FD_LIKELY( peers->slot_voted!=ULONG_MAX ) ) jsonp_ulong( peers->http, "value", peers->slot_voted );
257 0 : else jsonp_null ( peers->http, "value" );
258 0 : jsonp_close_envelope( peers->http );
259 0 : }
260 :
261 : void
262 0 : fd_gui_printf_turbine_slot( fd_gui_t * gui ) {
263 0 : jsonp_open_envelope( gui->http, "summary", "turbine_slot" );
264 0 : if( FD_LIKELY( gui->summary.slot_turbine!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_turbine );
265 0 : else jsonp_null ( gui->http, "value" );
266 0 : jsonp_close_envelope( gui->http );
267 0 : }
268 :
269 : void
270 0 : fd_gui_printf_reset_slot( fd_gui_t * gui ) {
271 0 : jsonp_open_envelope( gui->http, "summary", "reset_slot" );
272 0 : if( FD_LIKELY( gui->summary.slot_reset!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_reset );
273 0 : else jsonp_null ( gui->http, "value" );
274 0 : jsonp_close_envelope( gui->http );
275 0 : }
276 :
277 : void
278 0 : fd_gui_printf_storage_slot( fd_gui_t * gui ) {
279 0 : jsonp_open_envelope( gui->http, "summary", "storage_slot" );
280 0 : if( FD_LIKELY( gui->summary.slot_storage!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_storage );
281 0 : else jsonp_null ( gui->http, "value" );
282 0 : jsonp_close_envelope( gui->http );
283 0 : }
284 :
285 : void
286 0 : fd_gui_printf_active_fork_cnt( fd_gui_t * gui ) {
287 0 : jsonp_open_envelope( gui->http, "summary", "active_fork_count" );
288 0 : if( FD_LIKELY( gui->summary.active_fork_cnt!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.active_fork_cnt );
289 0 : else jsonp_null ( gui->http, "value" );
290 0 : jsonp_close_envelope( gui->http );
291 0 : }
292 :
293 : void
294 0 : fd_gui_printf_slot_caught_up( fd_gui_t * gui ) {
295 0 : jsonp_open_envelope( gui->http, "summary", "slot_caught_up" );
296 0 : if( FD_LIKELY( gui->summary.slot_caught_up!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_caught_up );
297 0 : else jsonp_null ( gui->http, "value" );
298 0 : jsonp_close_envelope( gui->http );
299 0 : }
300 :
301 : void
302 0 : fd_gui_printf_catch_up_history( fd_gui_t * gui ) {
303 0 : jsonp_open_envelope( gui->http, "summary", "catch_up_history" );
304 0 : jsonp_open_object( gui->http, "value" );
305 0 : jsonp_open_array( gui->http, "turbine" );
306 0 : for( ulong i=0UL; i<gui->summary.catch_up_turbine_sz; i+=2 ) {
307 0 : for( ulong j=gui->summary.catch_up_turbine[ i ]; j<=gui->summary.catch_up_turbine[ i+1UL ]; j++ ) {
308 0 : jsonp_ulong( gui->http, NULL, j );
309 0 : }
310 0 : }
311 0 : jsonp_close_array( gui->http );
312 0 : jsonp_open_array( gui->http, "repair" );
313 0 : for( ulong i=0UL; i<gui->summary.catch_up_repair_sz; i+=2 ) {
314 0 : for( ulong j=gui->summary.catch_up_repair[ i ]; j<=gui->summary.catch_up_repair[ i+1UL ]; j++ ) {
315 0 : jsonp_ulong( gui->http, NULL, j );
316 0 : }
317 0 : }
318 0 : jsonp_close_array( gui->http );
319 :
320 0 : if( FD_LIKELY( gui->summary.boot_progress.phase==FD_GUI_BOOT_PROGRESS_TYPE_CATCHING_UP ) ) {
321 0 : ulong min_slot = ULONG_MAX;
322 0 : long min_ts = LONG_MAX;
323 :
324 0 : #define SHREDS_REV_ITER( age_ns, code_staged, code_archive ) \
325 0 : do { \
326 0 : if( FD_UNLIKELY( gui->summary.boot_progress.catching_up_time_nanos==0L ) ) break; \
327 0 : for( ulong i=gui->shreds.staged_tail; i>gui->shreds.staged_head; i-- ) { \
328 0 : fd_gui_slot_staged_shred_event_t * event = &gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ]; \
329 0 : if( FD_UNLIKELY( event->timestamp < gui->summary.boot_progress.catching_up_time_nanos - age_ns ) ) break; \
330 0 : do { code_staged } while(0); \
331 0 : } \
332 0 : fd_gui_slot_t * s = fd_gui_get_slot( gui, gui->shreds.history_slot ); \
333 0 : while( s \
334 0 : && s->shreds.start_offset!=ULONG_MAX \
335 0 : && s->shreds.end_offset!=ULONG_MAX \
336 0 : && s->shreds.end_offset>s->shreds.start_offset \
337 0 : && gui->shreds.history[ (s->shreds.end_offset-1UL) % FD_GUI_SHREDS_HISTORY_SZ ].timestamp + age_ns > gui->summary.boot_progress.catching_up_time_nanos ) { \
338 0 : for( ulong i=s->shreds.end_offset; i>s->shreds.start_offset; i-- ) { \
339 0 : fd_gui_slot_history_shred_event_t * event = &gui->shreds.history[ (i-1UL) % FD_GUI_SHREDS_HISTORY_SZ ]; (void)event; \
340 0 : do { code_archive } while (0); \
341 0 : } \
342 0 : s = fd_gui_get_slot( gui, s->parent_slot ); \
343 0 : } \
344 0 : } while(0);
345 :
346 0 : SHREDS_REV_ITER(
347 0 : 15000000000,
348 0 : {
349 0 : min_slot = fd_ulong_min( min_slot, event->slot );
350 0 : min_ts = fd_long_min( min_ts, event->timestamp );
351 0 : },
352 0 : {
353 0 : min_slot = fd_ulong_min( min_slot, s->slot );
354 0 : min_ts = fd_long_min( min_ts, event->timestamp );
355 0 : }
356 0 : )
357 :
358 0 : jsonp_open_object( gui->http, "shreds" );
359 0 : jsonp_ulong ( gui->http, "reference_slot", min_slot );
360 0 : jsonp_long_as_str( gui->http, "reference_ts", min_ts );
361 :
362 0 : jsonp_open_array( gui->http, "slot_delta" );
363 0 : SHREDS_REV_ITER(
364 0 : 15000000000L,
365 0 : { jsonp_ulong( gui->http, NULL, event->slot-min_slot ); },
366 0 : { jsonp_ulong( gui->http, NULL, s->slot-min_slot ); }
367 0 : )
368 0 : jsonp_close_array( gui->http );
369 0 : jsonp_open_array( gui->http, "shred_idx" );
370 0 : SHREDS_REV_ITER(
371 0 : 15000000000L,
372 0 : {
373 0 : if( FD_LIKELY( event->shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, event->shred_idx );
374 0 : else jsonp_null ( gui->http, NULL );
375 0 : },
376 0 : {
377 0 : if( FD_LIKELY( event->shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, event->shred_idx );
378 0 : else jsonp_null ( gui->http, NULL );
379 0 : }
380 0 : )
381 0 : jsonp_close_array( gui->http );
382 0 : jsonp_open_array( gui->http, "event" );
383 0 : SHREDS_REV_ITER(
384 0 : 15000000000L,
385 0 : { jsonp_ulong( gui->http, NULL, event->event ); },
386 0 : { jsonp_ulong( gui->http, NULL, event->event ); }
387 0 : )
388 0 : jsonp_close_array( gui->http );
389 0 : jsonp_open_array( gui->http, "event_ts_delta" );
390 0 : SHREDS_REV_ITER(
391 0 : 15000000000L,
392 0 : { jsonp_long_as_str( gui->http, NULL, event->timestamp-min_ts ); },
393 0 : { jsonp_long_as_str( gui->http, NULL, event->timestamp-min_ts ); }
394 0 : )
395 0 : jsonp_close_array( gui->http );
396 0 : jsonp_close_object( gui->http );
397 0 : } else {
398 0 : jsonp_null( gui->http, "shreds" );
399 0 : }
400 :
401 0 : jsonp_close_object( gui->http );
402 0 : jsonp_close_envelope( gui->http );
403 0 : }
404 :
405 : void
406 0 : fd_gui_printf_vote_state( fd_gui_t * gui ) {
407 0 : jsonp_open_envelope( gui->http, "summary", "vote_state" );
408 0 : switch( gui->summary.vote_state ) {
409 0 : case FD_GUI_VOTE_STATE_NON_VOTING:
410 0 : jsonp_string( gui->http, "value", "non-voting" );
411 0 : break;
412 0 : case FD_GUI_VOTE_STATE_VOTING:
413 0 : jsonp_string( gui->http, "value", "voting" );
414 0 : break;
415 0 : case FD_GUI_VOTE_STATE_DELINQUENT:
416 0 : jsonp_string( gui->http, "value", "delinquent" );
417 0 : break;
418 0 : default:
419 0 : FD_LOG_ERR(( "unknown vote state %d", gui->summary.vote_state ));
420 0 : }
421 0 : jsonp_close_envelope( gui->http );
422 0 : }
423 :
424 : void
425 0 : fd_gui_printf_skipped_history( fd_gui_t * gui, ulong epoch_idx ) {
426 0 : jsonp_open_envelope( gui->http, "slot", "skipped_history" );
427 0 : jsonp_open_array( gui->http, "value" );
428 0 : ulong start_slot = gui->epoch.epochs[ epoch_idx ].start_slot;
429 0 : ulong end_slot = gui->epoch.epochs[ epoch_idx ].end_slot;
430 0 : for( ulong s=start_slot; s<fd_ulong_min( end_slot, start_slot+FD_GUI_SLOTS_CNT ); s++ ) {
431 0 : if( FD_LIKELY( gui->summary.slot_completed==ULONG_MAX ) ) break;
432 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, s );
433 :
434 0 : if( FD_UNLIKELY( !slot ) ) continue;
435 0 : if( FD_UNLIKELY( slot->mine && slot->skipped ) ) jsonp_ulong( gui->http, NULL, slot->slot );
436 0 : }
437 0 : jsonp_close_array( gui->http );
438 0 : jsonp_close_envelope( gui->http );
439 0 : }
440 :
441 : void
442 0 : fd_gui_printf_skipped_history_cluster( fd_gui_t * gui, ulong epoch_idx ) {
443 0 : jsonp_open_envelope( gui->http, "slot", "skipped_history_cluster" );
444 0 : jsonp_open_array( gui->http, "value" );
445 0 : ulong start_slot = gui->epoch.epochs[ epoch_idx ].start_slot;
446 0 : ulong end_slot = gui->epoch.epochs[ epoch_idx ].end_slot;
447 0 : for( ulong s=start_slot; s<fd_ulong_min( end_slot, start_slot+FD_GUI_SLOTS_CNT ); s++ ) {
448 0 : if( FD_LIKELY( gui->summary.slot_completed==ULONG_MAX ) ) break;
449 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, s );
450 :
451 0 : if( FD_UNLIKELY( !slot ) ) continue;
452 0 : if( FD_UNLIKELY( slot->skipped ) ) jsonp_ulong( gui->http, NULL, slot->slot );
453 0 : }
454 0 : jsonp_close_array( gui->http );
455 0 : jsonp_close_envelope( gui->http );
456 0 : }
457 :
458 : /* TODO: deprecated */
459 : void
460 0 : fd_gui_printf_vote_latency_history( fd_gui_t * gui ) {
461 0 : jsonp_open_envelope( gui->http, "slot", "vote_latency_history" );
462 0 : jsonp_open_array( gui->http, "value" );
463 0 : FD_TEST( gui->summary.late_votes_sz % 2UL == 0UL );
464 0 : for( ulong i=0UL; i<gui->summary.late_votes_sz; i++ ) jsonp_ulong( gui->http, NULL, gui->summary.late_votes[ i ] );
465 0 : jsonp_close_array( gui->http );
466 0 : jsonp_close_envelope( gui->http );
467 0 : }
468 :
469 : void
470 0 : fd_gui_printf_late_votes_history( fd_gui_t * gui ) {
471 0 : jsonp_open_envelope( gui->http, "slot", "late_votes_history" );
472 0 : jsonp_open_object( gui->http, "value" );
473 0 : jsonp_open_array( gui->http, "slot" );
474 0 : for( ulong i=0UL; i<gui->summary.late_votes_sz; i++ ) jsonp_ulong( gui->http, NULL, gui->summary.late_votes[ i ] );
475 0 : jsonp_close_array( gui->http );
476 0 : jsonp_open_array( gui->http, "latency" );
477 0 : for( long i=0UL; i<(long)gui->summary.late_votes_sz-1L; i+=2L ) {
478 0 : FD_TEST( (ulong)i+1<gui->summary.late_votes_sz );
479 0 : ulong s = gui->summary.late_votes[ i ];
480 0 : ulong s2 = gui->summary.late_votes[ i + 1 ];
481 0 : for( ulong j=s; j<=fd_ulong_min( s2, s+FD_GUI_SLOTS_CNT ); j++ ) {
482 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, j );
483 0 : if( FD_UNLIKELY( slot && slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, NULL, slot->vote_latency );
484 0 : else jsonp_null( gui->http, NULL );
485 0 : }
486 0 : }
487 0 : jsonp_close_array( gui->http );
488 0 : jsonp_close_object( gui->http );
489 0 : jsonp_close_envelope( gui->http );
490 0 : }
491 :
492 : void
493 0 : fd_gui_printf_tps_history( fd_gui_t * gui ) {
494 0 : jsonp_open_envelope( gui->http, "summary", "tps_history" );
495 0 : jsonp_open_array( gui->http, "value" );
496 :
497 0 : for( ulong i=0UL; i<FD_GUI_TPS_HISTORY_SAMPLE_CNT; i++ ) {
498 0 : ulong idx = (gui->summary.estimated_tps_history_idx+i) % FD_GUI_TPS_HISTORY_SAMPLE_CNT;
499 0 : jsonp_open_array( gui->http, NULL );
500 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ][ 0 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
501 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ][ 1 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
502 0 : jsonp_double( gui->http, NULL, (double)(gui->summary.estimated_tps_history[ idx ][ 0 ] - gui->summary.estimated_tps_history[ idx ][ 1 ] - gui->summary.estimated_tps_history[ idx ][ 2 ])/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
503 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ][ 2 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
504 0 : jsonp_close_array( gui->http );
505 0 : }
506 :
507 0 : jsonp_close_array( gui->http );
508 0 : jsonp_close_envelope( gui->http );
509 0 : }
510 :
511 : void
512 0 : fd_gui_printf_startup_progress( fd_gui_t * gui ) {
513 0 : char const * phase;
514 :
515 0 : switch( gui->summary.startup_progress.phase ) {
516 0 : case FD_GUI_START_PROGRESS_TYPE_INITIALIZING:
517 0 : phase = "initializing";
518 0 : break;
519 0 : case FD_GUI_START_PROGRESS_TYPE_SEARCHING_FOR_FULL_SNAPSHOT:
520 0 : phase = "searching_for_full_snapshot";
521 0 : break;
522 0 : case FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT:
523 0 : phase = "downloading_full_snapshot";
524 0 : break;
525 0 : case FD_GUI_START_PROGRESS_TYPE_SEARCHING_FOR_INCREMENTAL_SNAPSHOT:
526 0 : phase = "searching_for_incremental_snapshot";
527 0 : break;
528 0 : case FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT:
529 0 : phase = "downloading_incremental_snapshot";
530 0 : break;
531 0 : case FD_GUI_START_PROGRESS_TYPE_CLEANING_BLOCK_STORE:
532 0 : phase = "cleaning_blockstore";
533 0 : break;
534 0 : case FD_GUI_START_PROGRESS_TYPE_CLEANING_ACCOUNTS:
535 0 : phase = "cleaning_accounts";
536 0 : break;
537 0 : case FD_GUI_START_PROGRESS_TYPE_LOADING_LEDGER:
538 0 : phase = "loading_ledger";
539 0 : break;
540 0 : case FD_GUI_START_PROGRESS_TYPE_PROCESSING_LEDGER:
541 0 : phase = "processing_ledger";
542 0 : break;
543 0 : case FD_GUI_START_PROGRESS_TYPE_STARTING_SERVICES:
544 0 : phase = "starting_services";
545 0 : break;
546 0 : case FD_GUI_START_PROGRESS_TYPE_HALTED:
547 0 : phase = "halted";
548 0 : break;
549 0 : case FD_GUI_START_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY:
550 0 : phase = "waiting_for_supermajority";
551 0 : break;
552 0 : case FD_GUI_START_PROGRESS_TYPE_RUNNING:
553 0 : phase = "running";
554 0 : break;
555 0 : default:
556 0 : FD_LOG_ERR(( "unknown phase %d", gui->summary.startup_progress.phase ));
557 0 : }
558 :
559 0 : jsonp_open_envelope( gui->http, "summary", "startup_progress" );
560 0 : jsonp_open_object( gui->http, "value" );
561 0 : jsonp_string( gui->http, "phase", phase );
562 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT) ) {
563 0 : char peer_addr[ 64 ];
564 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 ) );
565 :
566 0 : jsonp_string( gui->http, "downloading_full_snapshot_peer", peer_addr );
567 0 : jsonp_ulong( gui->http, "downloading_full_snapshot_slot", gui->summary.startup_progress.startup_full_snapshot_slot );
568 0 : jsonp_double( gui->http, "downloading_full_snapshot_elapsed_secs", gui->summary.startup_progress.startup_full_snapshot_elapsed_secs );
569 0 : jsonp_double( gui->http, "downloading_full_snapshot_remaining_secs", gui->summary.startup_progress.startup_full_snapshot_remaining_secs );
570 0 : jsonp_double( gui->http, "downloading_full_snapshot_throughput", gui->summary.startup_progress.startup_full_snapshot_throughput );
571 0 : jsonp_ulong( gui->http, "downloading_full_snapshot_total_bytes", gui->summary.startup_progress.startup_full_snapshot_total_bytes );
572 0 : jsonp_ulong( gui->http, "downloading_full_snapshot_current_bytes", gui->summary.startup_progress.startup_full_snapshot_current_bytes );
573 0 : } else {
574 0 : jsonp_null( gui->http, "downloading_full_snapshot_peer" );
575 0 : jsonp_null( gui->http, "downloading_full_snapshot_slot" );
576 0 : jsonp_null( gui->http, "downloading_full_snapshot_elapsed_secs" );
577 0 : jsonp_null( gui->http, "downloading_full_snapshot_remaining_secs" );
578 0 : jsonp_null( gui->http, "downloading_full_snapshot_throughput" );
579 0 : jsonp_null( gui->http, "downloading_full_snapshot_total_bytes" );
580 0 : jsonp_null( gui->http, "downloading_full_snapshot_current_bytes" );
581 0 : }
582 :
583 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT) ) {
584 0 : char peer_addr[ 64 ];
585 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 ) );
586 :
587 0 : jsonp_string( gui->http, "downloading_incremental_snapshot_peer", peer_addr );
588 0 : jsonp_ulong( gui->http, "downloading_incremental_snapshot_slot", gui->summary.startup_progress.startup_incremental_snapshot_slot );
589 0 : jsonp_double( gui->http, "downloading_incremental_snapshot_elapsed_secs", gui->summary.startup_progress.startup_incremental_snapshot_elapsed_secs );
590 0 : jsonp_double( gui->http, "downloading_incremental_snapshot_remaining_secs", gui->summary.startup_progress.startup_incremental_snapshot_remaining_secs );
591 0 : jsonp_double( gui->http, "downloading_incremental_snapshot_throughput", gui->summary.startup_progress.startup_incremental_snapshot_throughput );
592 0 : jsonp_ulong( gui->http, "downloading_incremental_snapshot_total_bytes", gui->summary.startup_progress.startup_incremental_snapshot_total_bytes );
593 0 : jsonp_ulong( gui->http, "downloading_incremental_snapshot_current_bytes", gui->summary.startup_progress.startup_incremental_snapshot_current_bytes );
594 0 : } else {
595 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_peer" );
596 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_slot" );
597 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_elapsed_secs" );
598 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_remaining_secs" );
599 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_throughput" );
600 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_total_bytes" );
601 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_current_bytes" );
602 0 : }
603 :
604 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUI_START_PROGRESS_TYPE_PROCESSING_LEDGER) ) {
605 0 : jsonp_ulong( gui->http, "ledger_slot", gui->summary.startup_progress.startup_ledger_slot );
606 0 : jsonp_ulong( gui->http, "ledger_max_slot", gui->summary.startup_progress.startup_ledger_max_slot );
607 0 : } else {
608 0 : jsonp_null( gui->http, "ledger_slot" );
609 0 : jsonp_null( gui->http, "ledger_max_slot" );
610 0 : }
611 :
612 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUI_START_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY ) && gui->summary.startup_progress.startup_waiting_for_supermajority_slot!=ULONG_MAX ) {
613 0 : jsonp_ulong( gui->http, "waiting_for_supermajority_slot", gui->summary.startup_progress.startup_waiting_for_supermajority_slot );
614 0 : jsonp_ulong( gui->http, "waiting_for_supermajority_stake_percent", gui->summary.startup_progress.startup_waiting_for_supermajority_stake_pct );
615 0 : } else {
616 0 : jsonp_null( gui->http, "waiting_for_supermajority_slot" );
617 0 : jsonp_null( gui->http, "waiting_for_supermajority_stake_percent" );
618 0 : }
619 0 : jsonp_close_object( gui->http );
620 0 : jsonp_close_envelope( gui->http );
621 0 : }
622 :
623 : void
624 0 : fd_gui_printf_block_engine( fd_gui_t * gui ) {
625 0 : jsonp_open_envelope( gui->http, "block_engine", "update" );
626 0 : jsonp_open_object( gui->http, "value" );
627 0 : jsonp_string( gui->http, "name", gui->block_engine.name );
628 0 : jsonp_string( gui->http, "url", gui->block_engine.url );
629 0 : jsonp_string( gui->http, "ip", gui->block_engine.ip_cstr );
630 0 : if( FD_LIKELY( gui->block_engine.status==1 ) ) jsonp_string( gui->http, "status", "connecting" );
631 0 : else if( FD_LIKELY( gui->block_engine.status==2 ) ) jsonp_string( gui->http, "status", "connected" );
632 0 : else jsonp_string( gui->http, "status", "disconnected" );
633 0 : jsonp_close_object( gui->http );
634 0 : jsonp_close_envelope( gui->http );
635 0 : }
636 :
637 : void
638 0 : fd_gui_printf_tiles( fd_gui_t * gui ) {
639 0 : jsonp_open_envelope( gui->http, "summary", "tiles" );
640 0 : jsonp_open_array( gui->http, "value" );
641 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
642 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
643 :
644 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
645 : /* bench tiles not reported */
646 0 : continue;
647 0 : }
648 :
649 0 : jsonp_open_object( gui->http, NULL );
650 0 : jsonp_string( gui->http, "kind", tile->name );
651 0 : jsonp_ulong( gui->http, "kind_id", tile->kind_id );
652 0 : jsonp_ulong( gui->http, "pid", fd_metrics_tile( tile->metrics )[ MIDX( GAUGE, TILE, PID ) ] );
653 0 : jsonp_close_object( gui->http );
654 0 : }
655 0 : jsonp_close_array( gui->http );
656 0 : jsonp_close_envelope( gui->http );
657 0 : }
658 :
659 : void
660 0 : fd_gui_printf_schedule_strategy( fd_gui_t * gui ) {
661 0 : jsonp_open_envelope( gui->http, "summary", "schedule_strategy" );
662 0 : char mode[10];
663 0 : switch (gui->summary.schedule_strategy) {
664 0 : case 0: strncpy( mode, "perf", sizeof(mode) ); break;
665 0 : case 1: strncpy( mode, "balanced", sizeof(mode) ); break;
666 0 : case 2: strncpy( mode, "revenue", sizeof(mode) ); break;
667 0 : default: FD_LOG_ERR(("unexpected schedule_strategy %d", gui->summary.schedule_strategy));
668 0 : }
669 0 : mode[ sizeof(mode) - 1] = '\0';
670 0 : jsonp_string( gui->http, "value", mode );
671 0 : jsonp_close_envelope( gui->http );
672 0 : }
673 :
674 : void
675 0 : fd_gui_printf_identity_balance( fd_gui_t * gui ) {
676 0 : jsonp_open_envelope( gui->http, "summary", "identity_balance" );
677 0 : jsonp_ulong_as_str( gui->http, "value", gui->summary.identity_account_balance );
678 0 : jsonp_close_envelope( gui->http );
679 0 : }
680 :
681 : void
682 0 : fd_gui_printf_vote_balance( fd_gui_t * gui ) {
683 0 : jsonp_open_envelope( gui->http, "summary", "vote_balance" );
684 0 : jsonp_ulong_as_str( gui->http, "value", gui->summary.vote_account_balance );
685 0 : jsonp_close_envelope( gui->http );
686 0 : }
687 :
688 : void
689 0 : fd_gui_printf_estimated_slot_duration_nanos( fd_gui_t * gui ) {
690 0 : jsonp_open_envelope( gui->http, "summary", "estimated_slot_duration_nanos" );
691 0 : jsonp_ulong( gui->http, "value", gui->summary.estimated_slot_duration_nanos );
692 0 : jsonp_close_envelope( gui->http );
693 0 : }
694 :
695 :
696 : void
697 0 : fd_gui_printf_root_slot( fd_gui_t * gui ) {
698 0 : jsonp_open_envelope( gui->http, "summary", "root_slot" );
699 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_rooted!=ULONG_MAX, gui->summary.slot_rooted, 0UL ) );
700 0 : jsonp_close_envelope( gui->http );
701 0 : }
702 :
703 : void
704 0 : fd_gui_printf_optimistically_confirmed_slot( fd_gui_t * gui ) {
705 0 : jsonp_open_envelope( gui->http, "summary", "optimistically_confirmed_slot" );
706 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_optimistically_confirmed!=ULONG_MAX, gui->summary.slot_optimistically_confirmed, 0UL ) );
707 0 : jsonp_close_envelope( gui->http );
708 0 : }
709 :
710 : void
711 0 : fd_gui_printf_completed_slot( fd_gui_t * gui ) {
712 0 : jsonp_open_envelope( gui->http, "summary", "completed_slot" );
713 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_completed!=ULONG_MAX, gui->summary.slot_completed, 0UL ) );
714 0 : jsonp_close_envelope( gui->http );
715 0 : }
716 :
717 : void
718 0 : fd_gui_printf_estimated_slot( fd_gui_t * gui ) {
719 0 : jsonp_open_envelope( gui->http, "summary", "estimated_slot" );
720 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_estimated!=ULONG_MAX, gui->summary.slot_estimated, 0UL ) );
721 0 : jsonp_close_envelope( gui->http );
722 0 : }
723 :
724 : void
725 : fd_gui_printf_skip_rate( fd_gui_t * gui,
726 0 : ulong epoch_idx ) {
727 0 : jsonp_open_envelope( gui->http, "summary", "skip_rate" );
728 0 : jsonp_open_object( gui->http, "value" );
729 0 : jsonp_ulong( gui->http, "epoch", gui->epoch.epochs[ epoch_idx ].epoch );
730 0 : if( FD_UNLIKELY( !gui->epoch.epochs[ epoch_idx ].my_total_slots ) ) jsonp_double( gui->http, "skip_rate", 0.0 );
731 0 : else jsonp_double( gui->http, "skip_rate", (double)gui->epoch.epochs[ epoch_idx ].my_skipped_slots/(double)gui->epoch.epochs[ epoch_idx ].my_total_slots );
732 0 : jsonp_close_object( gui->http );
733 0 : jsonp_close_envelope( gui->http );
734 0 : }
735 :
736 : void
737 : fd_gui_printf_epoch( fd_gui_t * gui,
738 0 : ulong epoch_idx ) {
739 0 : jsonp_open_envelope( gui->http, "epoch", "new" );
740 0 : jsonp_open_object( gui->http, "value" );
741 0 : jsonp_ulong( gui->http, "epoch", gui->epoch.epochs[ epoch_idx ].epoch );
742 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 );
743 0 : else jsonp_null( gui->http, "start_time_nanos" );
744 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 );
745 0 : else jsonp_null( gui->http, "end_time_nanos" );
746 0 : jsonp_ulong( gui->http, "start_slot", gui->epoch.epochs[ epoch_idx ].start_slot );
747 0 : jsonp_ulong( gui->http, "end_slot", gui->epoch.epochs[ epoch_idx ].end_slot );
748 0 : jsonp_ulong_as_str( gui->http, "excluded_stake_lamports", gui->epoch.epochs[ epoch_idx ].excluded_stake );
749 0 : jsonp_open_array( gui->http, "staked_pubkeys" );
750 0 : fd_epoch_leaders_t * lsched = gui->epoch.epochs[epoch_idx].lsched;
751 0 : for( ulong i=0UL; i<lsched->pub_cnt; i++ ) {
752 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
753 0 : fd_base58_encode_32( lsched->pub[ i ].uc, NULL, identity_base58 );
754 0 : jsonp_string( gui->http, NULL, identity_base58 );
755 0 : }
756 0 : jsonp_close_array( gui->http );
757 :
758 0 : jsonp_open_array( gui->http, "staked_lamports" );
759 0 : fd_vote_stake_weight_t * stakes = gui->epoch.epochs[epoch_idx].stakes;
760 0 : for( ulong i=0UL; i<lsched->pub_cnt; i++ ) jsonp_ulong_as_str( gui->http, NULL, stakes[ i ].stake );
761 0 : jsonp_close_array( gui->http );
762 :
763 0 : jsonp_open_array( gui->http, "leader_slots" );
764 0 : for( ulong i = 0; i < lsched->sched_cnt; i++ ) jsonp_ulong( gui->http, NULL, lsched->sched[ i ] );
765 0 : jsonp_close_array( gui->http );
766 0 : jsonp_close_object( gui->http );
767 0 : jsonp_close_envelope( gui->http );
768 0 : }
769 :
770 : static void
771 : fd_gui_printf_waterfall( fd_gui_t * gui,
772 : fd_gui_txn_waterfall_t const * prev,
773 0 : fd_gui_txn_waterfall_t const * cur ) {
774 0 : jsonp_open_object( gui->http, "waterfall" );
775 0 : jsonp_open_object( gui->http, "in" );
776 0 : jsonp_ulong( gui->http, "pack_cranked", cur->in.pack_cranked - prev->in.pack_cranked );
777 0 : jsonp_ulong( gui->http, "pack_retained", prev->out.pack_retained );
778 0 : jsonp_ulong( gui->http, "resolv_retained", prev->out.resolv_retained );
779 0 : jsonp_ulong( gui->http, "quic", cur->in.quic - prev->in.quic );
780 0 : jsonp_ulong( gui->http, "udp", cur->in.udp - prev->in.udp );
781 0 : jsonp_ulong( gui->http, "gossip", cur->in.gossip - prev->in.gossip );
782 0 : jsonp_ulong( gui->http, "block_engine", cur->in.block_engine - prev->in.block_engine );
783 0 : jsonp_close_object( gui->http );
784 :
785 0 : jsonp_open_object( gui->http, "out" );
786 0 : jsonp_ulong( gui->http, "net_overrun", cur->out.net_overrun - prev->out.net_overrun );
787 0 : jsonp_ulong( gui->http, "quic_overrun", cur->out.quic_overrun - prev->out.quic_overrun );
788 0 : jsonp_ulong( gui->http, "quic_frag_drop", cur->out.quic_frag_drop - prev->out.quic_frag_drop );
789 0 : jsonp_ulong( gui->http, "quic_abandoned", cur->out.quic_abandoned - prev->out.quic_abandoned );
790 0 : jsonp_ulong( gui->http, "tpu_quic_invalid", cur->out.tpu_quic_invalid - prev->out.tpu_quic_invalid );
791 0 : jsonp_ulong( gui->http, "tpu_udp_invalid", cur->out.tpu_udp_invalid - prev->out.tpu_udp_invalid );
792 0 : jsonp_ulong( gui->http, "verify_overrun", cur->out.verify_overrun - prev->out.verify_overrun );
793 0 : jsonp_ulong( gui->http, "verify_parse", cur->out.verify_parse - prev->out.verify_parse );
794 0 : jsonp_ulong( gui->http, "verify_failed", cur->out.verify_failed - prev->out.verify_failed );
795 0 : jsonp_ulong( gui->http, "verify_duplicate", cur->out.verify_duplicate - prev->out.verify_duplicate );
796 0 : jsonp_ulong( gui->http, "dedup_duplicate", cur->out.dedup_duplicate - prev->out.dedup_duplicate );
797 0 : jsonp_ulong( gui->http, "resolv_lut_failed", cur->out.resolv_lut_failed - prev->out.resolv_lut_failed );
798 0 : jsonp_ulong( gui->http, "resolv_expired", cur->out.resolv_expired - prev->out.resolv_expired );
799 0 : jsonp_ulong( gui->http, "resolv_ancient", cur->out.resolv_ancient - prev->out.resolv_ancient );
800 0 : jsonp_ulong( gui->http, "resolv_no_ledger", cur->out.resolv_no_ledger - prev->out.resolv_no_ledger );
801 0 : jsonp_ulong( gui->http, "resolv_retained", cur->out.resolv_retained );
802 0 : jsonp_ulong( gui->http, "pack_invalid", cur->out.pack_invalid - prev->out.pack_invalid );
803 0 : jsonp_ulong( gui->http, "pack_invalid_bundle", cur->out.pack_invalid_bundle - prev->out.pack_invalid_bundle );
804 0 : jsonp_ulong( gui->http, "pack_expired", cur->out.pack_expired - prev->out.pack_expired );
805 0 : jsonp_ulong( gui->http, "pack_already_executed", cur->out.pack_already_executed - prev->out.pack_already_executed );
806 0 : jsonp_ulong( gui->http, "pack_retained", cur->out.pack_retained );
807 0 : jsonp_ulong( gui->http, "pack_wait_full", cur->out.pack_wait_full - prev->out.pack_wait_full );
808 0 : jsonp_ulong( gui->http, "pack_leader_slow", cur->out.pack_leader_slow - prev->out.pack_leader_slow );
809 0 : jsonp_ulong( gui->http, "bank_invalid", cur->out.bank_invalid - prev->out.bank_invalid );
810 0 : jsonp_ulong( gui->http, "bank_nonce_already_advanced", cur->out.bank_nonce_already_advanced - prev->out.bank_nonce_already_advanced );
811 0 : jsonp_ulong( gui->http, "bank_nonce_advance_failed", cur->out.bank_nonce_advance_failed - prev->out.bank_nonce_advance_failed );
812 0 : jsonp_ulong( gui->http, "bank_nonce_wrong_blockhash", cur->out.bank_nonce_wrong_blockhash - prev->out.bank_nonce_wrong_blockhash );
813 0 : jsonp_ulong( gui->http, "block_success", cur->out.block_success - prev->out.block_success );
814 0 : jsonp_ulong( gui->http, "block_fail", cur->out.block_fail - prev->out.block_fail );
815 0 : jsonp_close_object( gui->http );
816 0 : jsonp_close_object( gui->http );
817 0 : }
818 :
819 : void
820 : fd_gui_printf_live_txn_waterfall( fd_gui_t * gui,
821 : fd_gui_txn_waterfall_t const * prev,
822 : fd_gui_txn_waterfall_t const * cur,
823 0 : ulong next_leader_slot ) {
824 0 : jsonp_open_envelope( gui->http, "summary", "live_txn_waterfall" );
825 0 : jsonp_open_object( gui->http, "value" );
826 0 : jsonp_ulong( gui->http, "next_leader_slot", next_leader_slot );
827 0 : fd_gui_printf_waterfall( gui, prev, cur );
828 0 : jsonp_close_object( gui->http );
829 0 : jsonp_close_envelope( gui->http );
830 0 : }
831 :
832 : static void
833 : fd_gui_printf_network_metrics( fd_gui_t * gui,
834 0 : fd_gui_network_stats_t const * cur ) {
835 0 : jsonp_open_array( gui->http, "ingress" );
836 0 : jsonp_ulong( gui->http, NULL, cur->in.turbine );
837 0 : jsonp_ulong( gui->http, NULL, cur->in.gossip );
838 0 : jsonp_ulong( gui->http, NULL, cur->in.tpu );
839 0 : jsonp_ulong( gui->http, NULL, cur->in.repair );
840 0 : jsonp_ulong( gui->http, NULL, cur->in.metric );
841 0 : jsonp_close_array( gui->http );
842 0 : jsonp_open_array( gui->http, "egress" );
843 0 : jsonp_ulong( gui->http, NULL, cur->out.turbine );
844 0 : jsonp_ulong( gui->http, NULL, cur->out.gossip );
845 0 : jsonp_ulong( gui->http, NULL, cur->out.tpu );
846 0 : jsonp_ulong( gui->http, NULL, cur->out.repair );
847 0 : jsonp_ulong( gui->http, NULL, cur->out.metric );
848 0 : jsonp_close_array( gui->http );
849 0 : }
850 :
851 : void
852 : fd_gui_printf_live_network_metrics( fd_gui_t * gui,
853 0 : fd_gui_network_stats_t const * cur ) {
854 0 : jsonp_open_envelope( gui->http, "summary", "live_network_metrics" );
855 0 : jsonp_open_object( gui->http, "value" );
856 0 : fd_gui_printf_network_metrics( gui, cur );
857 0 : jsonp_close_object( gui->http );
858 0 : jsonp_close_envelope( gui->http );
859 0 : }
860 :
861 : static void
862 : fd_gui_printf_tile_stats( fd_gui_t * gui,
863 : fd_gui_tile_stats_t const * prev,
864 0 : fd_gui_tile_stats_t const * cur ) {
865 0 : jsonp_open_object( gui->http, "tile_primary_metric" );
866 0 : jsonp_ulong( gui->http, "quic", cur->quic_conn_cnt );
867 0 : jsonp_double( gui->http, "bundle_rtt_smoothed_millis", (double)(cur->bundle_rtt_smoothed_nanos) / 1000000.0 );
868 :
869 0 : fd_histf_t bundle_rx_delay_hist_delta[ 1 ];
870 0 : fd_histf_subtract( &cur->bundle_rx_delay_hist, &prev->bundle_rx_delay_hist, bundle_rx_delay_hist_delta );
871 0 : ulong bundle_rx_delay_nanos_p90 = fd_histf_percentile( bundle_rx_delay_hist_delta, 90U, ULONG_MAX );
872 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 ));
873 :
874 0 : if( FD_LIKELY( cur->sample_time_nanos>prev->sample_time_nanos ) ) {
875 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) ));
876 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) ));
877 0 : } else {
878 0 : jsonp_ulong( gui->http, "net_in", 0 );
879 0 : jsonp_ulong( gui->http, "net_out", 0 );
880 0 : }
881 0 : if( FD_LIKELY( cur->verify_total_cnt>prev->verify_total_cnt ) ) {
882 0 : jsonp_double( gui->http, "verify", (double)(cur->verify_drop_cnt-prev->verify_drop_cnt) / (double)(cur->verify_total_cnt-prev->verify_total_cnt) );
883 0 : } else {
884 0 : jsonp_double( gui->http, "verify", 0.0 );
885 0 : }
886 0 : if( FD_LIKELY( cur->dedup_total_cnt>prev->dedup_total_cnt ) ) {
887 0 : jsonp_double( gui->http, "dedup", (double)(cur->dedup_drop_cnt-prev->dedup_drop_cnt) / (double)(cur->dedup_total_cnt-prev->dedup_total_cnt) );
888 0 : } else {
889 0 : jsonp_double( gui->http, "dedup", 0.0 );
890 0 : }
891 0 : jsonp_ulong( gui->http, "bank", cur->bank_txn_exec_cnt - prev->bank_txn_exec_cnt );
892 0 : jsonp_double( gui->http, "pack", !cur->pack_buffer_capacity ? 1.0 : (double)cur->pack_buffer_cnt/(double)cur->pack_buffer_capacity );
893 0 : jsonp_double( gui->http, "poh", 0.0 );
894 0 : jsonp_double( gui->http, "shred", 0.0 );
895 0 : jsonp_double( gui->http, "store", 0.0 );
896 0 : jsonp_close_object( gui->http );
897 0 : }
898 :
899 : void
900 : fd_gui_printf_live_tile_stats( fd_gui_t * gui,
901 : fd_gui_tile_stats_t const * prev,
902 0 : fd_gui_tile_stats_t const * cur ) {
903 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_primary_metric" );
904 0 : jsonp_open_object( gui->http, "value" );
905 0 : jsonp_ulong( gui->http, "next_leader_slot", 0UL );
906 0 : fd_gui_printf_tile_stats( gui, prev, cur );
907 0 : jsonp_close_object( gui->http );
908 0 : jsonp_close_envelope( gui->http );
909 0 : }
910 :
911 : static void
912 : fd_gui_printf_tile_timers( fd_gui_t * gui,
913 : fd_gui_tile_timers_t const * prev,
914 0 : fd_gui_tile_timers_t const * cur ) {
915 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
916 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
917 :
918 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
919 : /* bench tiles not reported */
920 0 : continue;
921 0 : }
922 :
923 0 : ulong cur_total = 0UL;
924 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++ ) cur_total += cur[ i ].timers[ j ];
925 :
926 0 : ulong prev_total = 0UL;
927 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++ ) prev_total += prev[ i ].timers[ j ];
928 :
929 0 : double idle_ratio;
930 0 : if( FD_UNLIKELY( cur_total==prev_total ) ) {
931 : /* The tile didn't sample timers since the last sample, unclear what
932 : idleness should be so send -1. NaN would be better but no NaN in
933 : JSON. */
934 0 : idle_ratio = -1;
935 0 : } else {
936 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 ];
937 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 ];
938 0 : idle_ratio = (double)(idle_time+backpressure_time) / (double)(cur_total - prev_total);
939 0 : }
940 :
941 0 : jsonp_double( gui->http, NULL, idle_ratio );
942 0 : }
943 0 : }
944 :
945 : static void
946 : fd_gui_printf_tile_metrics( fd_gui_t * gui,
947 : fd_gui_tile_timers_t const * prev,
948 0 : fd_gui_tile_timers_t const * cur ) {
949 0 : jsonp_open_array( gui->http, "timers" );
950 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
951 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
952 :
953 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
954 : /* bench tiles not reported */
955 0 : jsonp_null( gui->http, NULL );
956 0 : continue;
957 0 : }
958 :
959 0 : ulong cur_total = 0UL;
960 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++ ) cur_total += cur[ i ].timers[ j ];
961 :
962 0 : ulong prev_total = 0UL;
963 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++ ) prev_total += prev[ i ].timers[ j ];
964 :
965 0 : if( FD_UNLIKELY( cur_total==prev_total ) ) {
966 0 : jsonp_null( gui->http, NULL );
967 0 : } else {
968 0 : jsonp_open_array( gui->http, NULL );
969 0 : for (ulong j = 0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++) {
970 0 : double percent = ((double)(cur[ i ].timers[ j ] - prev[ i ].timers[ j ]) / (double)(cur_total-prev_total)) * 100.0;
971 0 : double percent_trunc = (double)((long)(percent * 100.0)) / 100.0;
972 0 : jsonp_double( gui->http, NULL, percent_trunc );
973 0 : }
974 0 : jsonp_close_array( gui->http );
975 0 : }
976 0 : }
977 0 : jsonp_close_array( gui->http );
978 :
979 0 : jsonp_open_array( gui->http, "sched_timers" );
980 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
981 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
982 :
983 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
984 : /* bench tiles not reported */
985 0 : jsonp_null( gui->http, NULL );
986 0 : continue;
987 0 : }
988 :
989 0 : ulong cur_total = 0UL;
990 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_CPU_REGIME_CNT; j++ ) cur_total += cur[ i ].sched_timers[ j ];
991 :
992 0 : ulong prev_total = 0UL;
993 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_CPU_REGIME_CNT; j++ ) prev_total += prev[ i ].sched_timers[ j ];
994 :
995 0 : if( FD_UNLIKELY( cur_total==prev_total ) ) {
996 0 : jsonp_null( gui->http, NULL );
997 0 : } else {
998 0 : jsonp_open_array( gui->http, NULL );
999 0 : for (ulong j = 0UL; j<FD_METRICS_ENUM_CPU_REGIME_CNT; j++) {
1000 0 : double percent = ((double)(cur[ i ].sched_timers[ j ] - prev[ i ].sched_timers[ j ]) / (double)(cur_total-prev_total)) * 100.0;
1001 0 : double percent_trunc = (double)((long)(percent * 100.0)) / 100.0;
1002 0 : jsonp_double( gui->http, NULL, percent_trunc );
1003 0 : }
1004 0 : jsonp_close_array( gui->http );
1005 0 : }
1006 0 : }
1007 0 : jsonp_close_array( gui->http );
1008 :
1009 0 : jsonp_open_array( gui->http, "in_backp" );
1010 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1011 0 : jsonp_bool( gui->http, NULL, cur[ i ].in_backp );
1012 0 : }
1013 0 : jsonp_close_array( gui->http );
1014 0 : jsonp_open_array( gui->http, "backp_msgs" );
1015 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1016 0 : jsonp_ulong( gui->http, NULL, cur[ i ].backp_cnt );
1017 0 : }
1018 0 : jsonp_close_array( gui->http );
1019 0 : jsonp_open_array( gui->http, "alive" );
1020 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1021 : /* We use a longer sampling window for this metric to minimize
1022 : false positives */
1023 0 : jsonp_ulong( gui->http, NULL, fd_ulong_if( cur[ i ].status==2U, 2UL, (ulong)(cur[ i ].heartbeat>prev[ i ].heartbeat) ) );
1024 0 : }
1025 0 : jsonp_close_array( gui->http );
1026 0 : jsonp_open_array( gui->http, "nvcsw" );
1027 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1028 0 : jsonp_ulong( gui->http, NULL, cur[ i ].nvcsw );
1029 0 : }
1030 0 : jsonp_close_array( gui->http );
1031 0 : jsonp_open_array( gui->http, "nivcsw" );
1032 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1033 0 : jsonp_ulong( gui->http, NULL, cur[ i ].nivcsw );
1034 0 : }
1035 0 : jsonp_close_array( gui->http );
1036 0 : jsonp_open_array( gui->http, "minflt" );
1037 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1038 0 : jsonp_ulong( gui->http, NULL, cur[ i ].minflt );
1039 0 : }
1040 0 : jsonp_close_array( gui->http );
1041 0 : jsonp_open_array( gui->http, "majflt" );
1042 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1043 0 : jsonp_ulong( gui->http, NULL, cur[ i ].majflt );
1044 0 : }
1045 0 : jsonp_close_array( gui->http );
1046 0 : jsonp_open_array( gui->http, "last_cpu" );
1047 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
1048 0 : jsonp_ulong( gui->http, NULL, cur[ i ].last_cpu );
1049 0 : }
1050 0 : jsonp_close_array( gui->http );
1051 0 : }
1052 :
1053 : void
1054 0 : fd_gui_printf_live_tile_timers( fd_gui_t * gui ) {
1055 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_timers" );
1056 0 : jsonp_open_array( gui->http, "value" );
1057 0 : fd_gui_tile_timers_t * cur = gui->summary.tile_timers_snap[ (gui->summary.tile_timers_snap_idx+(FD_GUI_TILE_TIMER_SNAP_CNT-1UL))%FD_GUI_TILE_TIMER_SNAP_CNT ];
1058 0 : fd_gui_tile_timers_t * prev = gui->summary.tile_timers_snap[ (gui->summary.tile_timers_snap_idx+(FD_GUI_TILE_TIMER_SNAP_CNT-2UL))%FD_GUI_TILE_TIMER_SNAP_CNT ];
1059 0 : fd_gui_printf_tile_timers( gui, prev, cur );
1060 0 : jsonp_close_array( gui->http );
1061 0 : jsonp_close_envelope( gui->http );
1062 0 : }
1063 :
1064 : void
1065 0 : fd_gui_printf_live_tile_metrics( fd_gui_t * gui ) {
1066 0 : fd_gui_tile_timers_t * cur = gui->summary.tile_timers_snap[ (gui->summary.tile_timers_snap_idx+(FD_GUI_TILE_TIMER_SNAP_CNT-1UL))%FD_GUI_TILE_TIMER_SNAP_CNT ];
1067 0 : fd_gui_tile_timers_t * prev = gui->summary.tile_timers_snap[ (gui->summary.tile_timers_snap_idx+(FD_GUI_TILE_TIMER_SNAP_CNT-2UL))%FD_GUI_TILE_TIMER_SNAP_CNT ];
1068 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_metrics" );
1069 0 : jsonp_open_object( gui->http, "value" );
1070 0 : fd_gui_printf_tile_metrics( gui, prev, cur );
1071 0 : jsonp_close_object( gui->http );
1072 0 : jsonp_close_envelope( gui->http );
1073 0 : }
1074 :
1075 : void
1076 0 : fd_gui_printf_estimated_tps( fd_gui_t * gui ) {
1077 0 : ulong idx = (gui->summary.estimated_tps_history_idx+FD_GUI_TPS_HISTORY_SAMPLE_CNT-1UL) % FD_GUI_TPS_HISTORY_SAMPLE_CNT;
1078 :
1079 0 : jsonp_open_envelope( gui->http, "summary", "estimated_tps" );
1080 0 : jsonp_open_object( gui->http, "value" );
1081 0 : jsonp_double( gui->http, "total", (double)gui->summary.estimated_tps_history[ idx ][ 0 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
1082 0 : jsonp_double( gui->http, "vote", (double)gui->summary.estimated_tps_history[ idx ][ 1 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
1083 0 : jsonp_double( gui->http, "nonvote_success", (double)(gui->summary.estimated_tps_history[ idx ][ 0 ] - gui->summary.estimated_tps_history[ idx ][ 1 ] - gui->summary.estimated_tps_history[ idx ][ 2 ])/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
1084 0 : jsonp_double( gui->http, "nonvote_failed", (double)gui->summary.estimated_tps_history[ idx ][ 2 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
1085 0 : jsonp_close_object( gui->http );
1086 0 : jsonp_close_envelope( gui->http );
1087 0 : }
1088 :
1089 : static int
1090 : fd_gui_gossip_contains( fd_gui_t const * gui,
1091 0 : uchar const * pubkey ) {
1092 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
1093 0 : if( FD_UNLIKELY( !memcmp( gui->gossip.peers[ i ].pubkey->uc, pubkey, 32 ) ) ) return 1;
1094 0 : }
1095 0 : return 0;
1096 0 : }
1097 :
1098 : static int
1099 : fd_gui_vote_acct_contains( fd_gui_t const * gui,
1100 0 : uchar const * pubkey ) {
1101 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
1102 0 : if( FD_UNLIKELY( !memcmp( gui->vote_account.vote_accounts[ i ].pubkey, pubkey, 32 ) ) ) return 1;
1103 0 : }
1104 0 : return 0;
1105 0 : }
1106 :
1107 : static int
1108 : fd_gui_validator_info_contains( fd_gui_t const * gui,
1109 0 : uchar const * pubkey ) {
1110 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
1111 0 : if( FD_UNLIKELY( !memcmp( gui->validator_info.info[ i ].pubkey, pubkey, 32 ) ) ) return 1;
1112 0 : }
1113 0 : return 0;
1114 0 : }
1115 :
1116 : static void
1117 : fd_gui_printf_peer( fd_gui_t * gui,
1118 0 : uchar const * identity_pubkey ) {
1119 0 : ulong gossip_idx = ULONG_MAX;
1120 0 : ulong info_idx = ULONG_MAX;
1121 0 : ulong vote_idxs[ FD_GUI_MAX_PEER_CNT ] = {0};
1122 0 : ulong vote_idx_cnt = 0UL;
1123 :
1124 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
1125 0 : if( FD_UNLIKELY( !memcmp( gui->gossip.peers[ i ].pubkey->uc, identity_pubkey, 32 ) ) ) {
1126 0 : gossip_idx = i;
1127 0 : break;
1128 0 : }
1129 0 : }
1130 :
1131 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
1132 0 : if( FD_UNLIKELY( !memcmp( gui->validator_info.info[ i ].pubkey, identity_pubkey, 32 ) ) ) {
1133 0 : info_idx = i;
1134 0 : break;
1135 0 : }
1136 0 : }
1137 :
1138 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
1139 0 : if( FD_UNLIKELY( !memcmp( gui->vote_account.vote_accounts[ i ].pubkey, identity_pubkey, 32 ) ) ) {
1140 0 : vote_idxs[ vote_idx_cnt++ ] = i;
1141 0 : }
1142 0 : }
1143 :
1144 0 : jsonp_open_object( gui->http, NULL );
1145 :
1146 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1147 0 : fd_base58_encode_32( identity_pubkey, NULL, identity_base58 );
1148 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
1149 :
1150 0 : if( FD_UNLIKELY( gossip_idx==ULONG_MAX ) ) {
1151 0 : jsonp_string( gui->http, "gossip", NULL );
1152 0 : } else {
1153 0 : jsonp_open_object( gui->http, "gossip" );
1154 :
1155 0 : char version[ 32 ];
1156 0 : FD_TEST( fd_cstr_printf( version, sizeof( version ), NULL, "%u.%u.%u", gui->gossip.peers[ gossip_idx ].version.major, gui->gossip.peers[ gossip_idx ].version.minor, gui->gossip.peers[ gossip_idx ].version.patch ) );
1157 0 : jsonp_string( gui->http, "version", version );
1158 0 : jsonp_null( gui->http, "client_id" ); /* TODO: Frankendancer support */
1159 0 : jsonp_ulong( gui->http, "feature_set", gui->gossip.peers[ gossip_idx ].version.feature_set );
1160 0 : jsonp_ulong( gui->http, "wallclock", gui->gossip.peers[ gossip_idx ].wallclock );
1161 0 : jsonp_ulong( gui->http, "shred_version", gui->gossip.peers[ gossip_idx ].shred_version );
1162 0 : jsonp_open_object( gui->http, "sockets" );
1163 0 : for( ulong j=0UL; j<12UL; j++ ) {
1164 0 : if( FD_LIKELY( !gui->gossip.peers[ gossip_idx ].sockets[ j ].ipv4 && !gui->gossip.peers[ gossip_idx ].sockets[ j ].port ) ) continue;
1165 0 : char const * tag;
1166 0 : switch( j ) {
1167 0 : case 0: tag = "gossip"; break;
1168 0 : case 1: tag = "rpc"; break;
1169 0 : case 2: tag = "rpc_pubsub"; break;
1170 0 : case 3: tag = "serve_repair"; break;
1171 0 : case 4: tag = "serve_repair_quic"; break;
1172 0 : case 5: tag = "tpu"; break;
1173 0 : case 6: tag = "tpu_quic"; break;
1174 0 : case 7: tag = "tvu"; break;
1175 0 : case 8: tag = "tvu_quic"; break;
1176 0 : case 9: tag = "tpu_forwards"; break;
1177 0 : case 10: tag = "tpu_forwards_quic"; break;
1178 0 : case 11: tag = "tpu_vote"; break;
1179 0 : }
1180 0 : char line[ 64 ];
1181 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 ) );
1182 0 : jsonp_string( gui->http, tag, line );
1183 0 : }
1184 0 : jsonp_close_object( gui->http );
1185 :
1186 0 : jsonp_close_object( gui->http );
1187 0 : }
1188 :
1189 0 : jsonp_open_array( gui->http, "vote" );
1190 0 : for( ulong i=0UL; i<vote_idx_cnt; i++ ) {
1191 0 : jsonp_open_object( gui->http, NULL );
1192 0 : char vote_account_base58[ FD_BASE58_ENCODED_32_SZ ];
1193 0 : fd_base58_encode_32( gui->vote_account.vote_accounts[ vote_idxs[ i ] ].vote_account->uc, NULL, vote_account_base58 );
1194 0 : jsonp_string( gui->http, "vote_account", vote_account_base58 );
1195 0 : jsonp_ulong_as_str( gui->http, "activated_stake", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].activated_stake );
1196 0 : jsonp_ulong( gui->http, "last_vote", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].last_vote );
1197 0 : jsonp_ulong( gui->http, "root_slot", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].root_slot );
1198 0 : jsonp_ulong( gui->http, "epoch_credits", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].epoch_credits );
1199 0 : jsonp_ulong( gui->http, "commission", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].commission );
1200 0 : jsonp_bool( gui->http, "delinquent", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].delinquent );
1201 0 : jsonp_close_object( gui->http );
1202 0 : }
1203 0 : jsonp_close_array( gui->http );
1204 :
1205 0 : if( FD_UNLIKELY( info_idx==ULONG_MAX ) ) {
1206 0 : jsonp_string( gui->http, "info", NULL );
1207 0 : } else {
1208 0 : jsonp_open_object( gui->http, "info" );
1209 0 : jsonp_string( gui->http, "name", gui->validator_info.info[ info_idx ].name );
1210 0 : jsonp_string( gui->http, "details", gui->validator_info.info[ info_idx ].details );
1211 0 : jsonp_string( gui->http, "website", gui->validator_info.info[ info_idx ].website );
1212 0 : jsonp_string( gui->http, "icon_url", gui->validator_info.info[ info_idx ].icon_uri );
1213 0 : jsonp_string( gui->http, "keybase_username", "" );
1214 0 : jsonp_close_object( gui->http );
1215 0 : }
1216 :
1217 0 : jsonp_close_object( gui->http );
1218 0 : }
1219 :
1220 : static void
1221 : peers_printf_node( fd_gui_peers_ctx_t * peers,
1222 0 : ulong contact_info_table_idx ) {
1223 0 : fd_gui_peers_node_t * peer = &peers->contact_info_table[ contact_info_table_idx ];
1224 :
1225 0 : jsonp_open_object( peers->http, NULL );
1226 :
1227 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1228 0 : fd_base58_encode_32( peer->pubkey.uc, NULL, identity_base58 );
1229 0 : jsonp_string( peers->http, "identity_pubkey", identity_base58 );
1230 :
1231 0 : jsonp_open_object( peers->http, "gossip" );
1232 :
1233 0 : char version[ 32 ];
1234 0 : FD_TEST( fd_cstr_printf( version, sizeof( version ), NULL, "%u.%u.%u", peer->contact_info.version.major, peer->contact_info.version.minor, peer->contact_info.version.patch ) );
1235 0 : jsonp_string( peers->http, "version", version );
1236 0 : jsonp_ulong( peers->http, "client_id", peer->contact_info.version.client );
1237 0 : jsonp_ulong( peers->http, "feature_set", peer->contact_info.version.feature_set );
1238 0 : jsonp_long( peers->http, "wallclock", peer->wallclock_nanos );
1239 0 : jsonp_ulong( peers->http, "shred_version", peer->contact_info.shred_version );
1240 0 : jsonp_open_object( peers->http, "sockets" );
1241 0 : for( ulong j=0UL; j<FD_GOSSIP_CONTACT_INFO_SOCKET_CNT; j++ ) {
1242 0 : char const * tag;
1243 0 : switch( j ) {
1244 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP: tag = "gossip"; break;
1245 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_SERVE_REPAIR_QUIC: tag = "serve_repair_quic"; break;
1246 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_RPC: tag = "rpc"; break;
1247 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_RPC_PUBSUB: tag = "rpc_pubsub"; break;
1248 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_SERVE_REPAIR: tag = "serve_repair"; break;
1249 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TPU: tag = "tpu"; break;
1250 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_FORWARDS: tag = "tpu_forwards"; break;
1251 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_FORWARDS_QUIC: tag = "tpu_forwards_quic"; break;
1252 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_QUIC: tag = "tpu_quic"; break;
1253 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_VOTE: tag = "tpu_vote"; break;
1254 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TVU: tag = "tvu"; break;
1255 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TVU_QUIC: tag = "tvu_quic"; break;
1256 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_VOTE_QUIC: tag = "tpu_vote_quic"; break;
1257 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_ALPENGLOW: tag = "alpenglow"; break;
1258 0 : default: tag = "unknown"; break;
1259 0 : }
1260 0 : uint ip4 = peer->contact_info.sockets[ j ].is_ipv6 ? 0U : peer->contact_info.sockets[ j ].ip4;
1261 0 : char line[ 64 ];
1262 0 : FD_TEST( fd_cstr_printf( line, sizeof( line ), NULL, FD_IP4_ADDR_FMT ":%hu", FD_IP4_ADDR_FMT_ARGS( ip4 ), fd_ushort_bswap( peer->contact_info.sockets[ j ].port ) ) );
1263 0 : jsonp_string( peers->http, tag, line );
1264 0 : }
1265 0 : jsonp_close_object( peers->http );
1266 :
1267 0 : if( FD_LIKELY( peer->country_code_idx!=UCHAR_MAX ) ) {
1268 0 : jsonp_string( peers->http, "country_code", peers->dbip.country_code[ peer->country_code_idx ] );
1269 0 : } else {
1270 0 : jsonp_null( peers->http, "country_code" );
1271 0 : }
1272 :
1273 0 : if( FD_LIKELY( peer->city_name_idx!=UINT_MAX ) ) {
1274 0 : jsonp_string( peers->http, "city_name", peers->dbip.city_name[ peer->city_name_idx ] );
1275 0 : } else {
1276 0 : jsonp_null( peers->http, "city_name" );
1277 0 : }
1278 :
1279 0 : jsonp_close_object( peers->http );
1280 :
1281 0 : if( FD_LIKELY( !peer->has_vote_info ) ) {
1282 0 : jsonp_open_array( peers->http, "vote" );
1283 0 : jsonp_close_array( peers->http );
1284 0 : } else {
1285 0 : jsonp_open_array( peers->http, "vote" );
1286 0 : jsonp_open_object( peers->http, NULL );
1287 0 : char vote_account_base58[ FD_BASE58_ENCODED_32_SZ ];
1288 0 : fd_base58_encode_32( peer->vote_account.uc, NULL, vote_account_base58 );
1289 0 : jsonp_string( peers->http, "vote_account", vote_account_base58 );
1290 0 : jsonp_ulong_as_str( peers->http, "activated_stake", peer->stake );
1291 0 : jsonp_ulong( peers->http, "last_vote", peer->last_vote_slot );
1292 0 : jsonp_ulong( peers->http, "epoch_credits", peer->epoch_credits );
1293 0 : jsonp_ulong( peers->http, "commission", peer->commission );
1294 0 : jsonp_ulong( peers->http, "root_slot", 0UL );
1295 0 : jsonp_bool( peers->http, "delinquent", peer->delinquent );
1296 0 : jsonp_close_object( peers->http );
1297 0 : jsonp_close_array( peers->http );
1298 0 : }
1299 :
1300 0 : fd_gui_config_parse_info_t * node_info = fd_gui_peers_node_info_map_ele_query( peers->node_info_map, &peer->pubkey, NULL, peers->node_info_pool );
1301 0 : if( FD_UNLIKELY( !node_info ) ) {
1302 0 : jsonp_string( peers->http, "info", NULL );
1303 0 : } else {
1304 0 : jsonp_open_object( peers->http, "info" );
1305 0 : jsonp_string( peers->http, "name", node_info->name );
1306 0 : jsonp_string( peers->http, "details", node_info->details );
1307 0 : jsonp_string( peers->http, "website", node_info->website );
1308 0 : jsonp_string( peers->http, "icon_url", node_info->icon_uri );
1309 0 : jsonp_string( peers->http, "keybase_username", node_info->keybase_username );
1310 0 : jsonp_close_object( peers->http );
1311 0 : }
1312 :
1313 0 : jsonp_close_object( peers->http );
1314 0 : }
1315 :
1316 : void
1317 : fd_gui_peers_printf_nodes( fd_gui_peers_ctx_t * peers,
1318 : int * actions,
1319 : ulong * idxs,
1320 0 : ulong count ) {
1321 0 : jsonp_open_envelope( peers->http, "peers", "update" );
1322 0 : jsonp_open_object( peers->http, "value" );
1323 0 : jsonp_open_array( peers->http, "add" );
1324 0 : for( ulong i=0UL; i<count; i++ ) if( FD_UNLIKELY( actions[ i ]==FD_GUI_PEERS_NODE_ADD ) ) peers_printf_node( peers, idxs[ i ] );
1325 0 : jsonp_close_array( peers->http );
1326 :
1327 0 : jsonp_open_array( peers->http, "update" );
1328 0 : for( ulong i=0UL; i<count; i++ ) if( FD_UNLIKELY( actions[ i ]==FD_GUI_PEERS_NODE_UPDATE ) ) peers_printf_node( peers, idxs[ i ] );
1329 0 : jsonp_close_array( peers->http );
1330 :
1331 0 : jsonp_open_array( peers->http, "remove" );
1332 0 : for( ulong i=0UL; i<count; i++ ) {
1333 0 : if( FD_UNLIKELY( actions[ i ]==FD_GUI_PEERS_NODE_DELETE ) ) {
1334 0 : jsonp_open_object( peers->http, NULL );
1335 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1336 0 : fd_base58_encode_32( peers->contact_info_table[ idxs[ i ] ].pubkey.uc, NULL, identity_base58 );
1337 0 : jsonp_string( peers->http, "identity_pubkey", identity_base58 );
1338 0 : jsonp_close_object( peers->http );
1339 0 : }
1340 0 : }
1341 0 : jsonp_close_array( peers->http );
1342 0 : jsonp_close_object( peers->http );
1343 0 : jsonp_close_envelope( peers->http );
1344 0 : }
1345 :
1346 : void
1347 0 : fd_gui_peers_printf_node_all( fd_gui_peers_ctx_t * peers ) {
1348 0 : jsonp_open_envelope( peers->http, "peers", "update" );
1349 0 : jsonp_open_object( peers->http, "value" );
1350 0 : jsonp_open_array( peers->http, "add" );
1351 : /* We can iter through the bandwidth tracking table since it will always be populated */
1352 0 : for( fd_gui_peers_bandwidth_tracking_fwd_iter_t iter = fd_gui_peers_bandwidth_tracking_fwd_iter_init( peers->bw_tracking, &FD_GUI_PEERS_BW_TRACKING_INGRESS_SORT_KEY, peers->contact_info_table ), j = 0UL;
1353 0 : !fd_gui_peers_bandwidth_tracking_fwd_iter_done( iter );
1354 0 : iter = fd_gui_peers_bandwidth_tracking_fwd_iter_next( iter, peers->contact_info_table ), j++ ) {
1355 0 : ulong contact_info_table_idx = fd_gui_peers_bandwidth_tracking_fwd_iter_idx( iter );
1356 0 : peers_printf_node( peers, contact_info_table_idx );
1357 0 : }
1358 0 : jsonp_close_array( peers->http );
1359 0 : jsonp_open_array( peers->http, "update" );
1360 0 : jsonp_close_array( peers->http );
1361 0 : jsonp_open_array( peers->http, "remove" );
1362 0 : jsonp_close_array( peers->http );
1363 0 : jsonp_close_object( peers->http );
1364 0 : jsonp_close_envelope( peers->http );
1365 0 : }
1366 :
1367 : void
1368 : fd_gui_printf_peers_gossip_update( fd_gui_t * gui,
1369 : ulong const * updated,
1370 : ulong updated_cnt,
1371 : fd_pubkey_t const * removed,
1372 : ulong removed_cnt,
1373 : ulong const * added,
1374 0 : ulong added_cnt ) {
1375 0 : jsonp_open_envelope( gui->http, "peers", "update" );
1376 0 : jsonp_open_object( gui->http, "value" );
1377 0 : jsonp_open_array( gui->http, "add" );
1378 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1379 0 : int actually_added = !fd_gui_vote_acct_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc ) &&
1380 0 : !fd_gui_validator_info_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
1381 0 : if( FD_LIKELY( !actually_added ) ) continue;
1382 :
1383 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
1384 0 : }
1385 0 : jsonp_close_array( gui->http );
1386 :
1387 0 : jsonp_open_array( gui->http, "update" );
1388 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1389 0 : int actually_added = !fd_gui_vote_acct_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc ) &&
1390 0 : !fd_gui_validator_info_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
1391 0 : if( FD_LIKELY( actually_added ) ) continue;
1392 :
1393 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
1394 0 : }
1395 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
1396 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ updated[ i ] ].pubkey->uc );
1397 0 : }
1398 0 : jsonp_close_array( gui->http );
1399 :
1400 0 : jsonp_open_array( gui->http, "remove" );
1401 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
1402 0 : int actually_removed = !fd_gui_vote_acct_contains( gui, removed[ i ].uc ) &&
1403 0 : !fd_gui_validator_info_contains( gui, removed[ i ].uc );
1404 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
1405 :
1406 0 : jsonp_open_object( gui->http, NULL );
1407 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1408 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
1409 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
1410 0 : jsonp_close_object( gui->http );
1411 0 : }
1412 0 : jsonp_close_array( gui->http );
1413 0 : jsonp_close_object( gui->http );
1414 0 : jsonp_close_envelope( gui->http );
1415 0 : }
1416 :
1417 : void
1418 : fd_gui_printf_peers_vote_account_update( fd_gui_t * gui,
1419 : ulong const * updated,
1420 : ulong updated_cnt,
1421 : fd_pubkey_t const * removed,
1422 : ulong removed_cnt,
1423 : ulong const * added,
1424 0 : ulong added_cnt ) {
1425 0 : jsonp_open_envelope( gui->http, "peers", "update" );
1426 0 : jsonp_open_object( gui->http, "value" );
1427 0 : jsonp_open_array( gui->http, "add" );
1428 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1429 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
1430 0 : !fd_gui_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
1431 0 : if( FD_LIKELY( !actually_added ) ) continue;
1432 :
1433 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
1434 0 : }
1435 0 : jsonp_close_array( gui->http );
1436 :
1437 0 : jsonp_open_array( gui->http, "update" );
1438 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1439 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
1440 0 : !fd_gui_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
1441 0 : if( FD_LIKELY( actually_added ) ) continue;
1442 :
1443 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
1444 0 : }
1445 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
1446 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ updated[ i ] ].pubkey->uc );
1447 0 : }
1448 0 : jsonp_close_array( gui->http );
1449 :
1450 0 : jsonp_open_array( gui->http, "remove" );
1451 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
1452 0 : int actually_removed = !fd_gui_gossip_contains( gui, removed[ i ].uc) &&
1453 0 : !fd_gui_validator_info_contains( gui, removed[ i ].uc);
1454 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
1455 :
1456 0 : jsonp_open_object( gui->http, NULL );
1457 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1458 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
1459 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
1460 0 : jsonp_close_object( gui->http );
1461 0 : }
1462 0 : jsonp_close_array( gui->http );
1463 0 : jsonp_close_object( gui->http );
1464 0 : jsonp_close_envelope( gui->http );
1465 0 : }
1466 :
1467 : void
1468 : fd_gui_printf_peers_validator_info_update( fd_gui_t * gui,
1469 : ulong const * updated,
1470 : ulong updated_cnt,
1471 : fd_pubkey_t const * removed,
1472 : ulong removed_cnt,
1473 : ulong const * added,
1474 0 : ulong added_cnt ) {
1475 0 : jsonp_open_envelope( gui->http, "peers", "update" );
1476 0 : jsonp_open_object( gui->http, "value" );
1477 0 : jsonp_open_array( gui->http, "add" );
1478 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1479 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
1480 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1481 0 : if( FD_LIKELY( !actually_added ) ) continue;
1482 :
1483 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1484 0 : }
1485 0 : jsonp_close_array( gui->http );
1486 :
1487 0 : jsonp_open_array( gui->http, "update" );
1488 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1489 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
1490 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1491 0 : if( FD_LIKELY( actually_added ) ) continue;
1492 :
1493 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1494 0 : }
1495 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
1496 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ updated[ i ] ].pubkey->uc );
1497 0 : }
1498 0 : jsonp_close_array( gui->http );
1499 :
1500 0 : jsonp_open_array( gui->http, "remove" );
1501 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
1502 0 : int actually_removed = !fd_gui_gossip_contains( gui, removed[ i ].uc ) &&
1503 0 : !fd_gui_vote_acct_contains( gui, removed[ i ].uc );
1504 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
1505 :
1506 0 : jsonp_open_object( gui->http, NULL );
1507 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1508 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
1509 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
1510 0 : jsonp_close_object( gui->http );
1511 0 : }
1512 0 : jsonp_close_array( gui->http );
1513 0 : jsonp_close_object( gui->http );
1514 0 : jsonp_close_envelope( gui->http );
1515 0 : }
1516 :
1517 : void
1518 0 : fd_gui_printf_peers_all( fd_gui_t * gui ) {
1519 0 : jsonp_open_envelope( gui->http, "peers", "update" );
1520 0 : jsonp_open_object( gui->http, "value" );
1521 0 : jsonp_open_array( gui->http, "add" );
1522 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
1523 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ i ].pubkey->uc );
1524 0 : }
1525 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
1526 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ i ].pubkey->uc );
1527 0 : if( FD_UNLIKELY( actually_added ) ) {
1528 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ i ].pubkey->uc );
1529 0 : }
1530 0 : }
1531 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
1532 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ i ].pubkey->uc ) &&
1533 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ i ].pubkey->uc );
1534 0 : if( FD_UNLIKELY( actually_added ) ) {
1535 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ i ].pubkey->uc );
1536 0 : }
1537 0 : }
1538 0 : jsonp_close_array( gui->http );
1539 0 : jsonp_close_object( gui->http );
1540 0 : jsonp_close_envelope( gui->http );
1541 0 : }
1542 :
1543 : static void
1544 : fd_gui_printf_ts_tile_timers( fd_gui_t * gui,
1545 : fd_gui_tile_timers_t const * prev,
1546 0 : fd_gui_tile_timers_t const * cur ) {
1547 0 : jsonp_open_object( gui->http, NULL );
1548 0 : jsonp_ulong_as_str( gui->http, "timestamp_nanos", 0 );
1549 0 : jsonp_open_array( gui->http, "tile_timers" );
1550 0 : fd_gui_printf_tile_timers( gui, prev, cur );
1551 0 : jsonp_close_array( gui->http );
1552 0 : jsonp_close_object( gui->http );
1553 0 : }
1554 :
1555 : void
1556 : fd_gui_printf_slot( fd_gui_t * gui,
1557 0 : ulong _slot ) {
1558 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
1559 :
1560 0 : char const * level;
1561 0 : switch( slot->level ) {
1562 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1563 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1564 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1565 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1566 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1567 0 : default: level = "unknown"; break;
1568 0 : }
1569 :
1570 0 : fd_gui_slot_t * parent_slot = fd_gui_get_slot( gui, slot->parent_slot );
1571 0 : long duration_nanos = LONG_MAX;
1572 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1573 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1574 0 : }
1575 :
1576 0 : jsonp_open_envelope( gui->http, "slot", "update" );
1577 0 : jsonp_open_object( gui->http, "value" );
1578 0 : fd_gui_leader_slot_t * lslot = fd_gui_get_leader_slot( gui, _slot );
1579 0 : jsonp_open_object( gui->http, "publish" );
1580 0 : jsonp_ulong( gui->http, "slot", _slot );
1581 0 : jsonp_bool( gui->http, "mine", slot->mine );
1582 0 : if( FD_UNLIKELY( slot->vote_slot!=ULONG_MAX ) ) jsonp_ulong( gui->http, "vote_slot", slot->vote_slot );
1583 0 : else jsonp_null( gui->http, "vote_slot" );
1584 0 : if( FD_UNLIKELY( slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, "vote_latency", slot->vote_latency );
1585 0 : else jsonp_null( gui->http, "vote_latency" );
1586 :
1587 0 : if( FD_UNLIKELY( lslot && lslot->leader_start_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
1588 0 : else jsonp_null ( gui->http, "start_timestamp_nanos" );
1589 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 );
1590 0 : else jsonp_null ( gui->http, "target_end_timestamp_nanos" );
1591 :
1592 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1593 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1594 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1595 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1596 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
1597 0 : jsonp_string( gui->http, "level", level );
1598 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX
1599 0 : || slot->vote_txn_cnt==UINT_MAX
1600 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1601 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->total_txn_cnt - slot->vote_txn_cnt - slot->nonvote_failed_txn_cnt );
1602 0 : if( FD_UNLIKELY( slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1603 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed_txn_cnt );
1604 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX
1605 0 : || slot->failed_txn_cnt==UINT_MAX
1606 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1607 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_txn_cnt - (slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt) );
1608 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX
1609 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1610 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt );
1611 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1612 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1613 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1614 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1615 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
1616 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
1617 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1618 0 : else jsonp_ulong_as_str( gui->http, "transaction_fee", slot->transaction_fee );
1619 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1620 0 : else jsonp_ulong_as_str( gui->http, "priority_fee", slot->priority_fee );
1621 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1622 0 : else jsonp_ulong_as_str( gui->http, "tips", slot->tips );
1623 0 : jsonp_close_object( gui->http );
1624 0 : jsonp_close_object( gui->http );
1625 0 : jsonp_close_envelope( gui->http );
1626 0 : }
1627 :
1628 : void
1629 : fd_gui_printf_summary_ping( fd_gui_t * gui,
1630 0 : ulong id ) {
1631 0 : jsonp_open_envelope( gui->http, "summary", "ping" );
1632 0 : jsonp_ulong( gui->http, "id", id );
1633 0 : jsonp_null( gui->http, "value" );
1634 0 : jsonp_close_envelope( gui->http );
1635 0 : }
1636 :
1637 : void
1638 : fd_gui_printf_slot_rankings_request( fd_gui_t * gui,
1639 : ulong id,
1640 0 : int mine ) {
1641 0 : ulong epoch = ULONG_MAX;
1642 0 : for( ulong i = 0UL; i<2UL; i++ ) {
1643 0 : if( FD_LIKELY( gui->epoch.has_epoch[ i ] ) ) {
1644 : /* the "current" epoch is the smallest */
1645 0 : epoch = fd_ulong_min( epoch, gui->epoch.epochs[ i ].epoch );
1646 0 : }
1647 0 : }
1648 0 : ulong epoch_idx = epoch % 2UL;
1649 :
1650 0 : fd_gui_slot_rankings_t * rankings = fd_ptr_if( mine, (fd_gui_slot_rankings_t *)gui->epoch.epochs[ epoch_idx ].my_rankings, (fd_gui_slot_rankings_t *)gui->epoch.epochs[ epoch_idx ].rankings );
1651 :
1652 0 : jsonp_open_envelope( gui->http, "slot", "query_rankings" );
1653 0 : jsonp_ulong( gui->http, "id", id );
1654 0 : jsonp_open_object( gui->http, "value" );
1655 :
1656 0 : #define OUTPUT_RANKING_ARRAY(field) \
1657 0 : jsonp_open_array( gui->http, "slots_" FD_STRINGIFY(field) ); \
1658 0 : for( ulong i = 0UL; i<fd_ulong_if( epoch==ULONG_MAX, 0UL, FD_GUI_SLOT_RANKINGS_SZ ); i++ ) { \
1659 0 : if( FD_UNLIKELY( rankings->field[ i ].slot==ULONG_MAX ) ) break; \
1660 0 : jsonp_ulong( gui->http, NULL, rankings->field[ i ].slot ); \
1661 0 : } \
1662 0 : jsonp_close_array( gui->http ); \
1663 0 : jsonp_open_array( gui->http, "vals_" FD_STRINGIFY(field) ); \
1664 0 : for( ulong i = 0UL; i<fd_ulong_if( epoch==ULONG_MAX, 0UL, FD_GUI_SLOT_RANKINGS_SZ ); i++ ) { \
1665 0 : if( FD_UNLIKELY( rankings->field[ i ].slot==ULONG_MAX ) ) break; \
1666 0 : jsonp_ulong( gui->http, NULL, rankings->field[ i ].value ); \
1667 0 : } \
1668 0 : jsonp_close_array( gui->http )
1669 :
1670 0 : OUTPUT_RANKING_ARRAY( largest_tips );
1671 0 : OUTPUT_RANKING_ARRAY( largest_fees );
1672 0 : OUTPUT_RANKING_ARRAY( largest_rewards );
1673 0 : OUTPUT_RANKING_ARRAY( largest_rewards_per_cu );
1674 0 : OUTPUT_RANKING_ARRAY( largest_duration );
1675 0 : OUTPUT_RANKING_ARRAY( largest_compute_units );
1676 0 : OUTPUT_RANKING_ARRAY( largest_skipped );
1677 0 : OUTPUT_RANKING_ARRAY( smallest_tips );
1678 0 : OUTPUT_RANKING_ARRAY( smallest_fees );
1679 0 : OUTPUT_RANKING_ARRAY( smallest_rewards );
1680 0 : OUTPUT_RANKING_ARRAY( smallest_rewards_per_cu );
1681 0 : OUTPUT_RANKING_ARRAY( smallest_duration );
1682 0 : OUTPUT_RANKING_ARRAY( smallest_compute_units );
1683 0 : OUTPUT_RANKING_ARRAY( smallest_skipped );
1684 :
1685 0 : #undef OUTPUT_RANKING_ARRAY
1686 :
1687 0 : jsonp_close_object( gui->http );
1688 0 : jsonp_close_envelope( gui->http );
1689 0 : }
1690 :
1691 : void
1692 : fd_gui_printf_slot_request( fd_gui_t * gui,
1693 : ulong _slot,
1694 0 : ulong id ) {
1695 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
1696 :
1697 0 : char const * level;
1698 0 : switch( slot->level ) {
1699 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1700 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1701 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1702 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1703 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1704 0 : default: level = "unknown"; break;
1705 0 : }
1706 :
1707 0 : fd_gui_slot_t * parent_slot = fd_gui_get_slot( gui, slot->parent_slot );
1708 0 : long duration_nanos = LONG_MAX;
1709 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1710 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1711 0 : }
1712 :
1713 0 : jsonp_open_envelope( gui->http, "slot", "query" );
1714 0 : jsonp_ulong( gui->http, "id", id );
1715 0 : jsonp_open_object( gui->http, "value" );
1716 0 : fd_gui_leader_slot_t * lslot = fd_gui_get_leader_slot( gui, _slot );
1717 :
1718 0 : jsonp_open_object( gui->http, "publish" );
1719 0 : jsonp_ulong( gui->http, "slot", _slot );
1720 0 : jsonp_bool( gui->http, "mine", slot->mine );
1721 0 : if( FD_UNLIKELY( slot->vote_slot!=ULONG_MAX ) ) jsonp_ulong( gui->http, "vote_slot", slot->vote_slot );
1722 0 : else jsonp_null( gui->http, "vote_slot" );
1723 0 : if( FD_UNLIKELY( slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, "vote_latency", slot->vote_latency );
1724 0 : else jsonp_null( gui->http, "vote_latency" );
1725 :
1726 0 : if( FD_UNLIKELY( lslot && lslot->leader_start_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
1727 0 : else jsonp_null ( gui->http, "start_timestamp_nanos" );
1728 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 );
1729 0 : else jsonp_null ( gui->http, "target_end_timestamp_nanos" );
1730 :
1731 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1732 0 : jsonp_string( gui->http, "level", level );
1733 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1734 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1735 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1736 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
1737 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX
1738 0 : || slot->vote_txn_cnt==UINT_MAX
1739 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1740 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->total_txn_cnt - slot->vote_txn_cnt - slot->nonvote_failed_txn_cnt );
1741 0 : if( FD_UNLIKELY( slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1742 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed_txn_cnt );
1743 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX
1744 0 : || slot->failed_txn_cnt==UINT_MAX
1745 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1746 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_txn_cnt - (slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt) );
1747 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX
1748 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1749 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt );
1750 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1751 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1752 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1753 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1754 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
1755 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
1756 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1757 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
1758 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1759 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
1760 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1761 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
1762 0 : jsonp_close_object( gui->http );
1763 :
1764 0 : jsonp_close_object( gui->http );
1765 0 : jsonp_close_envelope( gui->http );
1766 0 : }
1767 :
1768 : void
1769 : fd_gui_printf_slot_transactions_request( fd_gui_t * gui,
1770 : ulong _slot,
1771 0 : ulong id ) {
1772 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
1773 :
1774 0 : char const * level;
1775 0 : switch( slot->level ) {
1776 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1777 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1778 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1779 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1780 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1781 0 : default: level = "unknown"; break;
1782 0 : }
1783 :
1784 0 : fd_gui_slot_t * parent_slot = fd_gui_get_slot( gui, slot->parent_slot );
1785 0 : long duration_nanos = LONG_MAX;
1786 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1787 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1788 0 : }
1789 :
1790 0 : jsonp_open_envelope( gui->http, "slot", "query" );
1791 0 : jsonp_ulong( gui->http, "id", id );
1792 0 : jsonp_open_object( gui->http, "value" );
1793 0 : fd_gui_leader_slot_t * lslot = fd_gui_get_leader_slot( gui, _slot );
1794 :
1795 0 : jsonp_open_object( gui->http, "publish" );
1796 0 : jsonp_ulong( gui->http, "slot", _slot );
1797 0 : jsonp_bool( gui->http, "mine", slot->mine );
1798 0 : if( FD_UNLIKELY( slot->vote_slot!=ULONG_MAX ) ) jsonp_ulong( gui->http, "vote_slot", slot->vote_slot );
1799 0 : else jsonp_null( gui->http, "vote_slot" );
1800 0 : if( FD_UNLIKELY( slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, "vote_latency", slot->vote_latency );
1801 0 : else jsonp_null( gui->http, "vote_latency" );
1802 :
1803 0 : if( FD_UNLIKELY( lslot && lslot->leader_start_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
1804 0 : else jsonp_null ( gui->http, "start_timestamp_nanos" );
1805 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 );
1806 0 : else jsonp_null ( gui->http, "target_end_timestamp_nanos" );
1807 :
1808 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1809 0 : jsonp_string( gui->http, "level", level );
1810 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1811 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1812 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1813 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
1814 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX
1815 0 : || slot->vote_txn_cnt==UINT_MAX
1816 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1817 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->total_txn_cnt - slot->vote_txn_cnt - slot->nonvote_failed_txn_cnt );
1818 0 : if( FD_UNLIKELY( slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1819 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed_txn_cnt );
1820 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX
1821 0 : || slot->failed_txn_cnt==UINT_MAX
1822 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1823 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_txn_cnt - (slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt) );
1824 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX
1825 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1826 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt );
1827 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1828 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1829 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1830 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1831 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
1832 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
1833 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1834 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
1835 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1836 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
1837 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1838 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
1839 0 : jsonp_close_object( gui->http );
1840 :
1841 0 : if( FD_UNLIKELY( lslot && lslot->unbecame_leader ) ) {
1842 0 : jsonp_open_object( gui->http, "limits" );
1843 0 : jsonp_ulong( gui->http, "used_total_block_cost", lslot->scheduler_stats->limits_usage->block_cost );
1844 0 : jsonp_ulong( gui->http, "used_total_vote_cost", lslot->scheduler_stats->limits_usage->vote_cost );
1845 0 : jsonp_ulong( gui->http, "used_total_bytes", lslot->scheduler_stats->limits_usage->block_data_bytes );
1846 0 : jsonp_ulong( gui->http, "used_total_microblocks", lslot->scheduler_stats->limits_usage->microblocks );
1847 0 : jsonp_open_array( gui->http, "used_account_write_costs" );
1848 0 : for( ulong i = 0; i<FD_PACK_TOP_WRITERS_CNT; i++ ) {
1849 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;
1850 :
1851 0 : jsonp_open_object( gui->http, NULL );
1852 0 : char account_base58[ FD_BASE58_ENCODED_32_SZ ];
1853 0 : fd_base58_encode_32( lslot->scheduler_stats->limits_usage->top_writers[ i ].key.b, NULL, account_base58 );
1854 0 : jsonp_string( gui->http, "account", account_base58 );
1855 0 : jsonp_ulong( gui->http, "cost", lslot->scheduler_stats->limits_usage->top_writers[ i ].total_cost );
1856 0 : jsonp_close_object( gui->http );
1857 0 : }
1858 0 : jsonp_close_array( gui->http );
1859 :
1860 0 : jsonp_ulong( gui->http, "max_total_block_cost", lslot->scheduler_stats->limits->max_cost_per_block );
1861 0 : jsonp_ulong( gui->http, "max_total_vote_cost", lslot->scheduler_stats->limits->max_vote_cost_per_block );
1862 0 : jsonp_ulong( gui->http, "max_account_write_cost", lslot->scheduler_stats->limits->max_write_cost_per_acct );
1863 0 : jsonp_ulong( gui->http, "max_total_bytes", lslot->scheduler_stats->limits->max_data_bytes_per_block );
1864 0 : jsonp_ulong( gui->http, "max_total_microblocks", lslot->scheduler_stats->limits->max_microblocks_per_block );
1865 0 : jsonp_close_object( gui->http );
1866 :
1867 0 : jsonp_open_object( gui->http, "scheduler_stats" );
1868 0 : char block_hash_base58[ FD_BASE58_ENCODED_32_SZ ];
1869 0 : fd_base58_encode_32( lslot->block_hash.uc, NULL, block_hash_base58 );
1870 0 : jsonp_string( gui->http, "block_hash", block_hash_base58 );
1871 :
1872 0 : switch( lslot->scheduler_stats->end_slot_reason ) {
1873 0 : case FD_PACK_END_SLOT_REASON_TIME: {
1874 0 : jsonp_string( gui->http, "end_slot_reason", "timeout" );
1875 0 : break;
1876 0 : }
1877 0 : case FD_PACK_END_SLOT_REASON_MICROBLOCK: {
1878 0 : jsonp_string( gui->http, "end_slot_reason", "microblock_limit" );
1879 0 : break;
1880 0 : }
1881 0 : case FD_PACK_END_SLOT_REASON_LEADER_SWITCH: {
1882 0 : jsonp_string( gui->http, "end_slot_reason", "leader_switch" );
1883 0 : break;
1884 0 : }
1885 0 : default: FD_LOG_ERR(( "unreachable" ));
1886 0 : }
1887 0 : jsonp_open_array( gui->http, "slot_schedule_counts" );
1888 0 : for( ulong i = 0; i<FD_METRICS_COUNTER_PACK_TRANSACTION_SCHEDULE_CNT; i++ ) jsonp_ulong( gui->http, NULL, lslot->scheduler_stats->block_results[ i ] );
1889 0 : jsonp_close_array( gui->http );
1890 0 : jsonp_open_array( gui->http, "end_slot_schedule_counts" );
1891 0 : for( ulong i = 0; i<FD_METRICS_COUNTER_PACK_TRANSACTION_SCHEDULE_CNT; i++ ) jsonp_ulong( gui->http, NULL, lslot->scheduler_stats->end_block_results[ i ] );
1892 0 : jsonp_close_array( gui->http );
1893 :
1894 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 );
1895 0 : else jsonp_null( gui->http, "pending_smallest_cost" );
1896 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 );
1897 0 : else jsonp_null( gui->http, "pending_smallest_bytes" );
1898 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 );
1899 0 : else jsonp_null( gui->http, "pending_vote_smallest_cost" );
1900 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 );
1901 0 : else jsonp_null( gui->http, "pending_vote_smallest_bytes" );
1902 0 : jsonp_close_object( gui->http );
1903 :
1904 0 : } else {
1905 0 : jsonp_null( gui->http, "limits" );
1906 0 : jsonp_null( gui->http, "scheduler_stats" );
1907 0 : }
1908 :
1909 0 : int overwritten = lslot && (gui->pack_txn_idx - lslot->txs.start_offset)>FD_GUI_TXN_HISTORY_SZ;
1910 0 : int processed_all_microblocks = lslot && lslot->unbecame_leader &&
1911 0 : lslot->txs.start_offset!=ULONG_MAX &&
1912 0 : lslot->txs.end_offset!=ULONG_MAX &&
1913 0 : lslot->txs.microblocks_upper_bound!=USHORT_MAX &&
1914 0 : lslot->txs.begin_microblocks==lslot->txs.end_microblocks &&
1915 0 : lslot->txs.begin_microblocks==lslot->txs.microblocks_upper_bound;
1916 :
1917 0 : if( FD_LIKELY( !overwritten && processed_all_microblocks ) ) {
1918 0 : ulong txn_cnt = lslot->txs.end_offset-lslot->txs.start_offset;
1919 :
1920 0 : jsonp_open_object( gui->http, "transactions" );
1921 0 : jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
1922 0 : jsonp_long_as_str( gui->http, "target_end_timestamp_nanos", lslot->leader_end_time );
1923 0 : jsonp_open_array( gui->http, "txn_mb_start_timestamps_nanos" );
1924 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_GUI_TXN_HISTORY_SZ ]->timestamp_delta_start_nanos );
1925 0 : jsonp_close_array( gui->http );
1926 0 : jsonp_open_array( gui->http, "txn_mb_end_timestamps_nanos" );
1927 : /* clamp end_ts to start_ts + 1 */
1928 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1929 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + fd_long_max( (long)gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->timestamp_delta_end_nanos,
1930 0 : (long)gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->timestamp_delta_start_nanos + 1L ) );
1931 0 : }
1932 0 : jsonp_close_array( gui->http );
1933 0 : jsonp_open_array( gui->http, "txn_compute_units_requested" );
1934 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->compute_units_requested );
1935 0 : jsonp_close_array( gui->http );
1936 0 : jsonp_open_array( gui->http, "txn_compute_units_consumed" );
1937 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->compute_units_consumed );
1938 0 : jsonp_close_array( gui->http );
1939 0 : jsonp_open_array( gui->http, "txn_priority_fee" );
1940 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong_as_str( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->priority_fee );
1941 0 : jsonp_close_array( gui->http );
1942 0 : jsonp_open_array( gui->http, "txn_transaction_fee" );
1943 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong_as_str( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->transaction_fee );
1944 0 : jsonp_close_array( gui->http );
1945 0 : jsonp_open_array( gui->http, "txn_error_code" );
1946 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->error_code );
1947 0 : jsonp_close_array( gui->http );
1948 0 : jsonp_open_array( gui->http, "txn_from_bundle" );
1949 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_bool( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->flags & FD_GUI_TXN_FLAGS_FROM_BUNDLE );
1950 0 : jsonp_close_array( gui->http );
1951 0 : jsonp_open_array( gui->http, "txn_is_simple_vote" );
1952 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_bool( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->flags & FD_GUI_TXN_FLAGS_IS_SIMPLE_VOTE );
1953 0 : jsonp_close_array( gui->http );
1954 0 : jsonp_open_array( gui->http, "txn_bank_idx" );
1955 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->bank_idx );
1956 0 : jsonp_close_array( gui->http );
1957 0 : jsonp_open_array( gui->http, "txn_preload_end_timestamps_nanos" );
1958 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1959 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
1960 0 : long microblock_duration = (long)txn->timestamp_delta_end_nanos - (long)txn->timestamp_delta_start_nanos;
1961 0 : long timestamp_delta_preload_end = (long)txn->timestamp_delta_start_nanos + (long)((double)txn->txn_preload_end_pct * (double)microblock_duration / (double)UCHAR_MAX);
1962 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + timestamp_delta_preload_end );
1963 0 : }
1964 0 : jsonp_close_array( gui->http );
1965 0 : jsonp_open_array( gui->http, "txn_start_timestamps_nanos" );
1966 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1967 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
1968 0 : long microblock_duration = (long)txn->timestamp_delta_end_nanos - (long)txn->timestamp_delta_start_nanos;
1969 0 : long timestamp_delta_validate_end = (long)txn->timestamp_delta_start_nanos + (long)((double)txn->txn_start_pct * (double)microblock_duration / (double)UCHAR_MAX);
1970 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + timestamp_delta_validate_end );
1971 0 : }
1972 0 : jsonp_close_array( gui->http );
1973 0 : jsonp_open_array( gui->http, "txn_load_end_timestamps_nanos" );
1974 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1975 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
1976 0 : long microblock_duration = (long)txn->timestamp_delta_end_nanos - (long)txn->timestamp_delta_start_nanos;
1977 0 : long timestamp_delta_load_end = (long)txn->timestamp_delta_start_nanos + (long)((double)txn->txn_load_end_pct * (double)microblock_duration / (double)UCHAR_MAX);
1978 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + timestamp_delta_load_end );
1979 0 : }
1980 0 : jsonp_close_array( gui->http );
1981 0 : jsonp_open_array( gui->http, "txn_end_timestamps_nanos" );
1982 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1983 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
1984 0 : long microblock_duration = (long)txn->timestamp_delta_end_nanos - (long)txn->timestamp_delta_start_nanos;
1985 0 : long timestamp_delta_exec_end = (long)txn->timestamp_delta_start_nanos + (long)((double)txn->txn_end_pct * (double)microblock_duration / (double)UCHAR_MAX);
1986 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + timestamp_delta_exec_end );
1987 0 : }
1988 0 : jsonp_close_array( gui->http );
1989 0 : jsonp_open_array( gui->http, "txn_arrival_timestamps_nanos" );
1990 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_long_as_str( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->timestamp_arrival_nanos );
1991 0 : jsonp_close_array( gui->http );
1992 0 : jsonp_open_array( gui->http, "txn_tips" );
1993 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong_as_str( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->tips );
1994 0 : jsonp_close_array( gui->http );
1995 0 : jsonp_open_array( gui->http, "txn_source_ipv4" );
1996 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1997 0 : char addr[ 64 ];
1998 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_GUI_TXN_HISTORY_SZ ]->source_ipv4 ) );
1999 0 : jsonp_string( gui->http, NULL, addr );
2000 0 : }
2001 0 : jsonp_close_array( gui->http );
2002 0 : jsonp_open_array( gui->http, "txn_source_tpu" );
2003 0 : for( ulong i=0UL; i<txn_cnt; i++) {
2004 0 : switch ( gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->source_tpu ) {
2005 0 : case FD_TXN_M_TPU_SOURCE_QUIC: {
2006 0 : jsonp_string( gui->http, NULL, "quic");
2007 0 : break;
2008 0 : }
2009 0 : case FD_TXN_M_TPU_SOURCE_UDP : {
2010 0 : jsonp_string( gui->http, NULL, "udp");
2011 0 : break;
2012 0 : }
2013 0 : case FD_TXN_M_TPU_SOURCE_GOSSIP: {
2014 0 : jsonp_string( gui->http, NULL, "gossip");
2015 0 : break;
2016 0 : }
2017 0 : case FD_TXN_M_TPU_SOURCE_BUNDLE: {
2018 0 : jsonp_string( gui->http, NULL, "bundle");
2019 0 : break;
2020 0 : }
2021 0 : case FD_TXN_M_TPU_SOURCE_TXSEND: {
2022 0 : jsonp_string( gui->http, NULL, "send");
2023 0 : break;
2024 0 : }
2025 0 : default: FD_LOG_ERR(("unknown tpu"));
2026 0 : }
2027 0 : }
2028 0 : jsonp_close_array( gui->http );
2029 0 : jsonp_open_array( gui->http, "txn_microblock_id" );
2030 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->microblock_idx );
2031 0 : jsonp_close_array( gui->http );
2032 0 : jsonp_open_array( gui->http, "txn_landed" );
2033 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_bool( gui->http, NULL, gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->flags & FD_GUI_TXN_FLAGS_LANDED_IN_BLOCK );
2034 0 : jsonp_close_array( gui->http );
2035 0 : jsonp_open_array( gui->http, "txn_signature" );
2036 0 : for( ulong i=0UL; i<txn_cnt; i++) {
2037 0 : FD_BASE58_ENCODE_64_BYTES( gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->signature, encoded_signature );
2038 0 : jsonp_string( gui->http, NULL, encoded_signature );
2039 0 : }
2040 0 : jsonp_close_array( gui->http );
2041 0 : jsonp_close_object( gui->http );
2042 0 : } else {
2043 0 : jsonp_null( gui->http, "transactions" );
2044 0 : }
2045 :
2046 0 : jsonp_close_object( gui->http );
2047 0 : jsonp_close_envelope( gui->http );
2048 0 : }
2049 :
2050 : void
2051 : fd_gui_printf_slot_request_detailed( fd_gui_t * gui,
2052 : ulong _slot,
2053 0 : ulong id ) {
2054 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
2055 :
2056 0 : char const * level;
2057 0 : switch( slot->level ) {
2058 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
2059 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
2060 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
2061 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
2062 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
2063 0 : default: level = "unknown"; break;
2064 0 : }
2065 :
2066 0 : fd_gui_slot_t * parent_slot = fd_gui_get_slot( gui, slot->parent_slot );
2067 0 : long duration_nanos = LONG_MAX;
2068 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
2069 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
2070 0 : }
2071 :
2072 0 : jsonp_open_envelope( gui->http, "slot", "query" );
2073 0 : jsonp_ulong( gui->http, "id", id );
2074 0 : jsonp_open_object( gui->http, "value" );
2075 0 : fd_gui_leader_slot_t * lslot = fd_gui_get_leader_slot( gui, _slot );
2076 :
2077 0 : jsonp_open_object( gui->http, "publish" );
2078 0 : jsonp_ulong( gui->http, "slot", _slot );
2079 0 : jsonp_bool( gui->http, "mine", slot->mine );
2080 0 : if( FD_UNLIKELY( slot->vote_slot!=ULONG_MAX ) ) jsonp_ulong( gui->http, "vote_slot", slot->vote_slot );
2081 0 : else jsonp_null( gui->http, "vote_slot" );
2082 0 : if( FD_UNLIKELY( slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, "vote_latency", slot->vote_latency );
2083 0 : else jsonp_null( gui->http, "vote_latency" );
2084 :
2085 0 : if( FD_UNLIKELY( lslot && lslot->leader_start_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
2086 0 : else jsonp_null ( gui->http, "start_timestamp_nanos" );
2087 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 );
2088 0 : else jsonp_null ( gui->http, "target_end_timestamp_nanos" );
2089 :
2090 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
2091 0 : jsonp_string( gui->http, "level", level );
2092 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
2093 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
2094 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
2095 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
2096 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX
2097 0 : || slot->vote_txn_cnt==UINT_MAX
2098 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
2099 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->total_txn_cnt - slot->vote_txn_cnt - slot->nonvote_failed_txn_cnt );
2100 0 : if( FD_UNLIKELY( slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
2101 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed_txn_cnt );
2102 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX
2103 0 : || slot->failed_txn_cnt==UINT_MAX
2104 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
2105 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_txn_cnt - (slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt) );
2106 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX
2107 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
2108 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt );
2109 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
2110 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
2111 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
2112 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
2113 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
2114 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
2115 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
2116 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
2117 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
2118 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
2119 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
2120 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
2121 0 : jsonp_close_object( gui->http );
2122 :
2123 0 : if( FD_LIKELY( gui->summary.slot_completed!=ULONG_MAX && gui->summary.slot_completed>_slot ) ) {
2124 0 : fd_gui_printf_waterfall( gui, slot->waterfall_begin, slot->waterfall_end );
2125 :
2126 0 : fd_gui_leader_slot_t * lslot = fd_gui_get_leader_slot( gui, _slot );
2127 0 : if( FD_LIKELY( lslot && lslot->unbecame_leader ) ) {
2128 0 : jsonp_open_array( gui->http, "tile_timers" );
2129 0 : fd_gui_tile_timers_t const * prev_timer = lslot->tile_timers[ 0 ];
2130 0 : for( ulong i=1UL; i<lslot->tile_timers_sample_cnt; i++ ) {
2131 0 : fd_gui_tile_timers_t const * cur_timer = lslot->tile_timers[ i ];
2132 0 : fd_gui_printf_ts_tile_timers( gui, prev_timer, cur_timer );
2133 0 : prev_timer = cur_timer;
2134 0 : }
2135 0 : jsonp_close_array( gui->http );
2136 0 : } else {
2137 : /* Our tile timers were overwritten. */
2138 0 : jsonp_null( gui->http, "tile_timers" );
2139 0 : }
2140 :
2141 0 : if( FD_LIKELY( lslot && lslot->unbecame_leader ) ) {
2142 0 : jsonp_open_array( gui->http, "scheduler_counts" );
2143 : /* Unlike tile timers (which are counters), scheduler counts
2144 : are a gauge and we don't take a diff. */
2145 0 : for( ulong i=0UL; i<lslot->scheduler_counts_sample_cnt; i++ ) {
2146 0 : fd_gui_scheduler_counts_t const * cur = lslot->scheduler_counts[ i ];
2147 0 : jsonp_open_object( gui->http, NULL );
2148 0 : jsonp_long_as_str( gui->http, "timestamp_nanos", cur->sample_time_ns );
2149 0 : jsonp_ulong ( gui->http, "regular", cur->regular );
2150 0 : jsonp_ulong ( gui->http, "votes", cur->votes );
2151 0 : jsonp_ulong ( gui->http, "conflicting", cur->conflicting );
2152 0 : jsonp_ulong ( gui->http, "bundles", cur->bundles );
2153 0 : jsonp_close_object( gui->http );
2154 0 : }
2155 0 : jsonp_close_array( gui->http );
2156 0 : } else {
2157 : /* Our scheduler counts were overwritten. */
2158 0 : jsonp_null( gui->http, "scheduler_counts" );
2159 0 : }
2160 :
2161 0 : fd_gui_printf_tile_stats( gui, slot->tile_stats_begin, slot->tile_stats_end );
2162 0 : } else {
2163 0 : jsonp_null( gui->http, "waterfall" );
2164 0 : jsonp_null( gui->http, "tile_timers" );
2165 0 : jsonp_null( gui->http, "tile_primary_metric" );
2166 0 : }
2167 :
2168 0 : jsonp_close_object( gui->http );
2169 0 : jsonp_close_envelope( gui->http );
2170 0 : }
2171 :
2172 : void
2173 0 : fd_gui_printf_boot_progress( fd_gui_t * gui ) {
2174 0 : jsonp_open_envelope( gui->http, "summary", "boot_progress" );
2175 0 : jsonp_open_object( gui->http, "value" );
2176 0 : switch( gui->summary.boot_progress.phase ) {
2177 0 : case FD_GUI_BOOT_PROGRESS_TYPE_JOINING_GOSSIP: jsonp_string( gui->http, "phase", "joining_gossip" ); break;
2178 0 : case FD_GUI_BOOT_PROGRESS_TYPE_LOADING_FULL_SNAPSHOT: jsonp_string( gui->http, "phase", "loading_full_snapshot" ); break;
2179 0 : case FD_GUI_BOOT_PROGRESS_TYPE_LOADING_INCREMENTAL_SNAPSHOT: jsonp_string( gui->http, "phase", "loading_incremental_snapshot" ); break;
2180 0 : case FD_GUI_BOOT_PROGRESS_TYPE_CATCHING_UP: jsonp_string( gui->http, "phase", "catching_up" ); break;
2181 0 : case FD_GUI_BOOT_PROGRESS_TYPE_RUNNING: jsonp_string( gui->http, "phase", "running" ); break;
2182 0 : default: FD_LOG_ERR(( "unknown phase %d", gui->summary.boot_progress.phase ));
2183 0 : }
2184 :
2185 0 : jsonp_double( gui->http, "joining_gossip_elapsed_seconds", (double)(gui->summary.boot_progress.joining_gossip_time_nanos - gui->summary.startup_time_nanos) / 1e9 );
2186 :
2187 0 : #define HANDLE_SNAPSHOT_STATE(snapshot_type, snapshot_type_upper) \
2188 0 : if( FD_LIKELY( gui->summary.boot_progress.phase>=FD_GUI_BOOT_PROGRESS_TYPE_LOADING_##snapshot_type_upper##_SNAPSHOT )) { \
2189 0 : ulong snapshot_idx = FD_GUI_BOOT_PROGRESS_##snapshot_type_upper##_SNAPSHOT_IDX; \
2190 0 : jsonp_double ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_elapsed_seconds", (double)(gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].sample_time_nanos - gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].reset_time_nanos) / 1e9 ); \
2191 0 : jsonp_ulong ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_reset_count", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].reset_cnt ); \
2192 0 : jsonp_ulong ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_slot", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].slot ); \
2193 0 : jsonp_ulong_as_str( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_total_bytes_compressed", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].total_bytes_compressed ); \
2194 0 : jsonp_ulong_as_str( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_read_bytes_compressed", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].read_bytes_compressed ); \
2195 0 : jsonp_string ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_read_path", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].read_path ); \
2196 0 : jsonp_ulong_as_str( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_decompress_bytes_decompressed", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].decompress_bytes_decompressed ); \
2197 0 : jsonp_ulong_as_str( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_decompress_bytes_compressed", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].decompress_bytes_compressed ); \
2198 0 : jsonp_ulong_as_str( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_insert_bytes_decompressed", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].insert_bytes_decompressed ); \
2199 0 : jsonp_ulong ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_insert_accounts", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].insert_accounts_current ); \
2200 0 : } else { \
2201 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_elapsed_seconds" ); \
2202 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_reset_count" ); \
2203 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_slot" ); \
2204 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_total_bytes_compressed" ); \
2205 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_read_bytes_compressed" ); \
2206 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_read_path" ); \
2207 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_decompress_bytes_decompressed" ); \
2208 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_decompress_bytes_compressed" ); \
2209 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_insert_bytes_decompressed" ); \
2210 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_insert_accounts" ); \
2211 0 : }
2212 :
2213 0 : HANDLE_SNAPSHOT_STATE(full, FULL)
2214 0 : HANDLE_SNAPSHOT_STATE(incremental, INCREMENTAL)
2215 0 : #undef HANDLE_SNAPSHOT_STATE
2216 :
2217 0 : if( FD_LIKELY( gui->summary.boot_progress.phase>=FD_GUI_BOOT_PROGRESS_TYPE_CATCHING_UP ) ) jsonp_double( gui->http, "catching_up_elapsed_seconds", (double)(gui->summary.boot_progress.catching_up_time_nanos - gui->summary.boot_progress.loading_snapshot[ FD_GUI_BOOT_PROGRESS_INCREMENTAL_SNAPSHOT_IDX ].sample_time_nanos) / 1e9 );
2218 0 : else jsonp_null ( gui->http, "catching_up_elapsed_seconds" );
2219 :
2220 0 : if( FD_LIKELY( gui->summary.boot_progress.phase>=FD_GUI_BOOT_PROGRESS_TYPE_CATCHING_UP
2221 0 : && gui->summary.boot_progress.catching_up_first_replay_slot!=ULONG_MAX ) ) {
2222 0 : jsonp_ulong( gui->http, "catching_up_first_replay_slot", gui->summary.boot_progress.catching_up_first_replay_slot );
2223 0 : } else {
2224 0 : jsonp_null( gui->http, "catching_up_first_replay_slot" );
2225 0 : }
2226 :
2227 0 : jsonp_close_object( gui->http );
2228 0 : jsonp_close_envelope( gui->http );
2229 0 : }
2230 :
2231 : void
2232 : fd_gui_printf_peers_viewport_update( fd_gui_peers_ctx_t * peers,
2233 0 : ulong ws_conn_id ) {
2234 0 : jsonp_open_envelope( peers->http, "gossip", "view_update" );
2235 0 : jsonp_open_object( peers->http, "value" );
2236 0 : jsonp_open_array( peers->http, "changes" );
2237 :
2238 : /* loop over latest viewport */
2239 0 : FD_TEST( peers->client_viewports[ ws_conn_id ].connected );
2240 0 : if( FD_UNLIKELY( peers->client_viewports[ ws_conn_id ].row_cnt>FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ ) ) FD_LOG_ERR(("row_cnt=%lu ws_conn_id=%lu peers->active_ws_conn_id=%lu", peers->client_viewports[ ws_conn_id ].row_cnt, ws_conn_id, peers->active_ws_conn_id ));
2241 :
2242 0 : for( fd_gui_peers_live_table_fwd_iter_t iter = fd_gui_peers_live_table_fwd_iter_init( peers->live_table, &peers->client_viewports[ ws_conn_id ].sort_key, peers->contact_info_table ), j = 0;
2243 0 : !fd_gui_peers_live_table_fwd_iter_done( iter ) && j<peers->client_viewports[ ws_conn_id ].start_row+peers->client_viewports[ ws_conn_id ].row_cnt;
2244 0 : iter = fd_gui_peers_live_table_fwd_iter_next( iter, peers->contact_info_table ), j++ ) {
2245 0 : if( FD_LIKELY( j<peers->client_viewports[ ws_conn_id ].start_row ) ) continue;
2246 0 : fd_gui_peers_node_t const * cur = fd_gui_peers_live_table_fwd_iter_ele_const( iter, peers->contact_info_table );
2247 0 : fd_gui_peers_node_t * ref = &peers->client_viewports[ ws_conn_id ].viewport[ j-peers->client_viewports[ ws_conn_id ].start_row ];
2248 :
2249 : /* This code should be kept in sync with updates to
2250 : fd_gui_peers_live_table */
2251 0 : if( FD_UNLIKELY( cur->stake!=ref->stake ) ) {
2252 0 : jsonp_open_object( peers->http, NULL );
2253 0 : jsonp_ulong ( peers->http, "row_index", j );
2254 0 : jsonp_string( peers->http, "column_name", "Stake" );
2255 :
2256 0 : if( FD_UNLIKELY( cur->stake==ULONG_MAX ) ) jsonp_long ( peers->http, "new_value", -1 );
2257 0 : else jsonp_ulong( peers->http, "new_value", cur->stake );
2258 0 : jsonp_close_object( peers->http );
2259 0 : }
2260 :
2261 0 : if( FD_UNLIKELY( strncmp( cur->name, ref->name, sizeof(ref->name) ) ) ) {
2262 0 : jsonp_open_object( peers->http, NULL );
2263 0 : jsonp_ulong ( peers->http, "row_index", j );
2264 0 : jsonp_string( peers->http, "column_name", "Name" );
2265 0 : jsonp_string( peers->http, "new_value", cur->name );
2266 0 : jsonp_close_object( peers->http );
2267 0 : }
2268 :
2269 0 : if( FD_UNLIKELY( cur->country_code_idx!=ref->country_code_idx ) ) {
2270 0 : jsonp_open_object( peers->http, NULL );
2271 0 : jsonp_ulong ( peers->http, "row_index", j );
2272 0 : jsonp_string( peers->http, "column_name", "Country" );
2273 0 : jsonp_string( peers->http, "new_value", peers->dbip.country_code[ cur->country_code_idx ] );
2274 0 : jsonp_close_object( peers->http );
2275 0 : }
2276 :
2277 0 : if( FD_UNLIKELY( memcmp( cur->pubkey.uc, ref->pubkey.uc, 32UL ) ) ) {
2278 0 : jsonp_open_object( peers->http, NULL );
2279 0 : jsonp_ulong ( peers->http, "row_index", j );
2280 0 : jsonp_string( peers->http, "column_name", "Pubkey" );
2281 :
2282 0 : char pubkey_base58[ FD_BASE58_ENCODED_32_SZ ];
2283 0 : fd_base58_encode_32( cur->pubkey.uc, NULL, pubkey_base58 );
2284 0 : jsonp_string( peers->http, "new_value", pubkey_base58 );
2285 0 : jsonp_close_object( peers->http );
2286 0 : }
2287 :
2288 0 : uint ip4_after = cur->contact_info.sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP ].is_ipv6 ? 0U : cur->contact_info.sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP ].ip4;
2289 0 : uint ip4_before = ref->contact_info.sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP ].is_ipv6 ? 0U : ref->contact_info.sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP ].ip4;
2290 0 : if( FD_UNLIKELY( ip4_after!=ip4_before ) ) {
2291 0 : jsonp_open_object( peers->http, NULL );
2292 0 : jsonp_ulong ( peers->http, "row_index", j );
2293 0 : jsonp_string( peers->http, "column_name", "IP Addr" );
2294 :
2295 0 : char peer_addr[ 16 ]; /* 255.255.255.255 + '\0' */
2296 0 : FD_TEST( fd_cstr_printf_check( peer_addr, sizeof(peer_addr), NULL, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( ip4_after ) ) );
2297 0 : jsonp_string( peers->http, "new_value", peer_addr );
2298 0 : jsonp_close_object( peers->http );
2299 0 : }
2300 :
2301 0 : long cur_egress_push_kbps = cur->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema;
2302 0 : long ref_egress_push_kbps = ref->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema;
2303 0 : long cur_ingress_push_kbps = cur->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema;
2304 0 : long ref_ingress_push_kbps = ref->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema;
2305 0 : long cur_egress_pull_response_kbps = cur->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema;
2306 0 : long ref_egress_pull_response_kbps = ref->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema;
2307 0 : long cur_ingress_pull_response_kbps = cur->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema;
2308 0 : long ref_ingress_pull_response_kbps = ref->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema;
2309 :
2310 0 : if( FD_UNLIKELY( ref->valid && cur_ingress_pull_response_kbps!=ref_ingress_pull_response_kbps ) ) {
2311 0 : jsonp_open_object( peers->http, NULL );
2312 0 : jsonp_ulong ( peers->http, "row_index", j );
2313 0 : jsonp_string( peers->http, "column_name", "Ingress Pull" );
2314 0 : jsonp_long ( peers->http, "new_value", cur_ingress_pull_response_kbps );
2315 0 : jsonp_close_object( peers->http );
2316 0 : }
2317 :
2318 0 : if( FD_UNLIKELY( ref->valid && cur_ingress_push_kbps!=ref_ingress_push_kbps ) ) {
2319 0 : jsonp_open_object( peers->http, NULL );
2320 0 : jsonp_ulong ( peers->http, "row_index", j );
2321 0 : jsonp_string( peers->http, "column_name", "Ingress Push" );
2322 0 : jsonp_long ( peers->http, "new_value", cur_ingress_push_kbps );
2323 0 : jsonp_close_object( peers->http );
2324 0 : }
2325 :
2326 0 : if( FD_UNLIKELY( ref->valid && cur_egress_pull_response_kbps!=ref_egress_pull_response_kbps ) ) {
2327 0 : jsonp_open_object( peers->http, NULL );
2328 0 : jsonp_ulong ( peers->http, "row_index", j );
2329 0 : jsonp_string( peers->http, "column_name", "Egress Pull" );
2330 0 : jsonp_long ( peers->http, "new_value", cur_egress_pull_response_kbps );
2331 0 : jsonp_close_object( peers->http );
2332 0 : }
2333 :
2334 0 : if( FD_UNLIKELY( ref->valid && cur_egress_push_kbps!=ref_egress_push_kbps ) ) {
2335 0 : jsonp_open_object( peers->http, NULL );
2336 0 : jsonp_ulong ( peers->http, "row_index", j );
2337 0 : jsonp_string( peers->http, "column_name", "Egress Push" );
2338 0 : jsonp_long ( peers->http, "new_value", cur_egress_push_kbps );
2339 0 : jsonp_close_object( peers->http );
2340 0 : }
2341 :
2342 0 : }
2343 0 : jsonp_close_array( peers->http );
2344 0 : jsonp_close_object( peers->http );
2345 0 : jsonp_close_envelope( peers->http );
2346 0 : }
2347 :
2348 : void
2349 : fd_gui_printf_peers_viewport_request( fd_gui_peers_ctx_t * peers,
2350 : char const * key,
2351 : ulong ws_conn_id,
2352 0 : ulong request_id ) {
2353 0 : jsonp_open_envelope( peers->http, "gossip", key );
2354 0 : jsonp_ulong( peers->http, "id", request_id );
2355 0 : jsonp_open_object( peers->http, "value" );
2356 :
2357 0 : FD_TEST( peers->client_viewports[ ws_conn_id ].connected );
2358 0 : if( FD_UNLIKELY( peers->client_viewports[ ws_conn_id ].row_cnt>FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ ) ) FD_LOG_ERR(("row_cnt=%lu ws_conn_id=%lu peers->active_ws_conn_id=%lu", peers->client_viewports[ ws_conn_id ].row_cnt, ws_conn_id, peers->active_ws_conn_id ));
2359 0 : for( fd_gui_peers_live_table_fwd_iter_t iter = fd_gui_peers_live_table_fwd_iter_init( peers->live_table, &peers->client_viewports[ ws_conn_id ].sort_key, peers->contact_info_table ), j = 0;
2360 0 : !fd_gui_peers_live_table_fwd_iter_done( iter ) && j<peers->client_viewports[ ws_conn_id ].start_row+peers->client_viewports[ ws_conn_id ].row_cnt;
2361 0 : iter = fd_gui_peers_live_table_fwd_iter_next( iter, peers->contact_info_table ), j++ ) {
2362 0 : if( FD_LIKELY( j<peers->client_viewports[ ws_conn_id ].start_row ) ) continue;
2363 0 : fd_gui_peers_node_t const * cur = fd_gui_peers_live_table_fwd_iter_ele_const( iter, peers->contact_info_table );
2364 :
2365 0 : char row_index_cstr[ 32 ];
2366 0 : FD_TEST( fd_cstr_printf_check( row_index_cstr, sizeof(row_index_cstr), NULL, "%lu", + j ) );
2367 0 : jsonp_open_object( peers->http, row_index_cstr );
2368 : /* This code should be kept in sync with updates to
2369 : fd_gui_peers_live_table */
2370 0 : if( FD_UNLIKELY( cur->stake==ULONG_MAX ) ) jsonp_long ( peers->http, "Stake", -1 );
2371 0 : else jsonp_ulong( peers->http, "Stake", cur->stake );
2372 :
2373 0 : char pubkey_base58[ FD_BASE58_ENCODED_32_SZ ];
2374 0 : fd_base58_encode_32( cur->pubkey.uc, NULL, pubkey_base58 );
2375 0 : jsonp_string( peers->http, "Pubkey", pubkey_base58 );
2376 0 : jsonp_string( peers->http, "Name", cur->name );
2377 0 : jsonp_string( peers->http, "Country", peers->dbip.country_code[ cur->country_code_idx ] );
2378 :
2379 0 : uint ip4 = cur->contact_info.sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP ].is_ipv6 ? 0U : cur->contact_info.sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP ].ip4;
2380 0 : char peer_addr[ 16 ]; /* 255.255.255.255 + '\0' */
2381 0 : FD_TEST( fd_cstr_printf_check( peer_addr, sizeof(peer_addr), NULL, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( ip4 ) ) );
2382 0 : jsonp_string( peers->http, "IP Addr", peer_addr );
2383 :
2384 0 : long cur_egress_push_kbps = cur->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema;
2385 0 : long cur_ingress_push_kbps = cur->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema;
2386 0 : long cur_egress_pull_response_kbps = cur->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema;
2387 0 : long cur_ingress_pull_response_kbps = cur->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema;
2388 :
2389 0 : jsonp_long ( peers->http, "Ingress Pull", cur_ingress_pull_response_kbps );
2390 0 : jsonp_long ( peers->http, "Ingress Push", cur_ingress_push_kbps );
2391 0 : jsonp_long ( peers->http, "Egress Pull", cur_egress_pull_response_kbps );
2392 0 : jsonp_long ( peers->http, "Egress Push", cur_egress_push_kbps );
2393 :
2394 0 : jsonp_close_object( peers->http );
2395 0 : }
2396 :
2397 0 : jsonp_close_object( peers->http );
2398 0 : jsonp_close_envelope( peers->http );
2399 0 : }
2400 :
2401 : void
2402 0 : fd_gui_printf_peers_view_resize( fd_gui_peers_ctx_t * peers, ulong sz ) {
2403 0 : jsonp_open_envelope( peers->http, "gossip", "peers_size_update" );
2404 0 : jsonp_ulong( peers->http, "value", sz );
2405 0 : jsonp_close_envelope( peers->http );
2406 0 : }
2407 :
2408 : void
2409 0 : fd_gui_peers_printf_gossip_stats( fd_gui_peers_ctx_t * peers ) {
2410 0 : fd_gui_peers_gossip_stats_t * cur = peers->gossip_stats;
2411 :
2412 0 : jsonp_open_envelope( peers->http, "gossip", "network_stats" );
2413 0 : jsonp_open_object( peers->http, "value" );
2414 :
2415 0 : jsonp_open_object( peers->http, "health" );
2416 0 : jsonp_ulong ( peers->http, "num_push_messages_rx_success", cur->network_health_push_msg_rx_success );
2417 0 : jsonp_ulong ( peers->http, "num_push_messages_rx_failure", cur->network_health_push_msg_rx_failure );
2418 0 : jsonp_ulong ( peers->http, "num_push_entries_rx_success", cur->network_health_push_crds_rx_success );
2419 0 : jsonp_ulong ( peers->http, "num_push_entries_rx_failure", cur->network_health_push_crds_rx_failure );
2420 0 : jsonp_ulong ( peers->http, "num_push_entries_rx_duplicate", cur->network_health_push_crds_rx_duplicate );
2421 0 : jsonp_ulong ( peers->http, "num_pull_response_messages_rx_success", cur->network_health_pull_response_msg_rx_success );
2422 0 : jsonp_ulong ( peers->http, "num_pull_response_messages_rx_failure", cur->network_health_pull_response_msg_rx_failure );
2423 0 : jsonp_ulong ( peers->http, "num_pull_response_entries_rx_success", cur->network_health_pull_response_crds_rx_success );
2424 0 : jsonp_ulong ( peers->http, "num_pull_response_entries_rx_failure", cur->network_health_pull_response_crds_rx_failure );
2425 0 : jsonp_ulong ( peers->http, "num_pull_response_entries_rx_duplicate", cur->network_health_pull_response_crds_rx_duplicate );
2426 0 : jsonp_ulong_as_str( peers->http, "total_stake", cur->network_health_total_stake );
2427 0 : jsonp_ulong ( peers->http, "total_peers", cur->network_health_total_peers );
2428 0 : jsonp_ulong_as_str( peers->http, "connected_stake", cur->network_health_connected_stake );
2429 0 : jsonp_ulong ( peers->http, "connected_staked_peers", cur->network_health_connected_staked_peers );
2430 0 : jsonp_ulong ( peers->http, "connected_unstaked_peers", cur->network_health_connected_unstaked_peers );
2431 0 : jsonp_close_object( peers->http );
2432 :
2433 0 : jsonp_open_object( peers->http, "ingress" );
2434 :
2435 0 : jsonp_open_array( peers->http, "peer_names" );
2436 0 : for( ulong i=0UL; i<cur->network_ingress_peer_sz; i++ ) jsonp_string( peers->http, NULL, cur->network_ingress_peer_names[ i ] );
2437 0 : jsonp_close_array( peers->http );
2438 :
2439 0 : jsonp_open_array( peers->http, "peer_identities" );
2440 0 : for( ulong i=0UL; i<cur->network_ingress_peer_sz; i++ ) {
2441 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
2442 0 : fd_base58_encode_32( cur->network_ingress_peer_identities[ i ].uc, NULL, identity_base58 );
2443 0 : jsonp_string( peers->http, NULL, identity_base58 );
2444 0 : }
2445 0 : jsonp_close_array( peers->http );
2446 :
2447 0 : jsonp_open_array( peers->http, "peer_throughput" );
2448 0 : for( ulong i=0UL; i<cur->network_ingress_peer_sz; i++ ) jsonp_long( peers->http, NULL, cur->network_ingress_peer_bytes_per_sec[ i ] );
2449 0 : jsonp_close_array( peers->http );
2450 0 : jsonp_long( peers->http, "total_throughput", cur->network_ingress_total_bytes_per_sec );
2451 0 : jsonp_close_object( peers->http );
2452 :
2453 0 : jsonp_open_object( peers->http, "egress" );
2454 0 : jsonp_open_array( peers->http, "peer_names" );
2455 0 : for( ulong i=0UL; i<cur->network_egress_peer_sz; i++ ) jsonp_string( peers->http, NULL, cur->network_egress_peer_names[ i ] );
2456 0 : jsonp_close_array( peers->http );
2457 :
2458 0 : jsonp_open_array( peers->http, "peer_identities" );
2459 0 : for( ulong i=0UL; i<cur->network_egress_peer_sz; i++ ) {
2460 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
2461 0 : fd_base58_encode_32( cur->network_egress_peer_identities[ i ].uc, NULL, identity_base58 );
2462 0 : jsonp_string( peers->http, NULL, identity_base58 );
2463 0 : }
2464 0 : jsonp_close_array( peers->http );
2465 :
2466 0 : jsonp_open_array( peers->http, "peer_throughput" );
2467 0 : for( ulong i=0UL; i<cur->network_egress_peer_sz; i++ ) jsonp_long( peers->http, NULL, cur->network_egress_peer_bytes_per_sec[ i ] );
2468 0 : jsonp_close_array( peers->http );
2469 0 : jsonp_long( peers->http, "total_throughput", cur->network_egress_total_bytes_per_sec );
2470 0 : jsonp_close_object( peers->http );
2471 :
2472 0 : jsonp_open_object( peers->http, "storage" );
2473 : /* since these are gauges, we don't take a diff */
2474 0 : jsonp_ulong( peers->http, "capacity", cur->storage_capacity );
2475 0 : jsonp_ulong( peers->http, "expired_count", cur->storage_expired_cnt );
2476 0 : jsonp_ulong( peers->http, "evicted_count", cur->storage_evicted_cnt );
2477 0 : jsonp_open_array( peers->http, "count" );
2478 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_CRDS_VALUE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->storage_active_cnt[ i ] );
2479 0 : jsonp_close_array( peers->http );
2480 0 : jsonp_open_array( peers->http, "count_tx" );
2481 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_CRDS_VALUE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->storage_cnt_tx[ i ] );
2482 0 : jsonp_close_array( peers->http );
2483 0 : jsonp_open_array( peers->http, "bytes_tx" );
2484 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_CRDS_VALUE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->storage_bytes_tx[ i ] );
2485 0 : jsonp_close_array( peers->http );
2486 0 : jsonp_close_object( peers->http );
2487 0 : jsonp_open_object( peers->http, "messages" );
2488 0 : jsonp_open_array( peers->http, "num_bytes_rx" );
2489 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->messages_bytes_rx[ i ] );
2490 0 : jsonp_close_array( peers->http );
2491 0 : jsonp_open_array( peers->http, "num_bytes_tx" );
2492 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->messages_bytes_tx[ i ] );
2493 0 : jsonp_close_array( peers->http );
2494 0 : jsonp_open_array( peers->http, "num_messages_rx" );
2495 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->messages_count_rx[ i ] );
2496 0 : jsonp_close_array( peers->http );
2497 0 : jsonp_open_array( peers->http, "num_messages_tx" );
2498 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->messages_count_tx[ i ] );
2499 0 : jsonp_close_array( peers->http );
2500 0 : jsonp_close_object( peers->http );
2501 0 : jsonp_close_object( peers->http );
2502 0 : jsonp_close_envelope( peers->http );
2503 0 : }
2504 :
2505 : void
2506 0 : fd_gui_printf_shreds_staged( fd_gui_t * gui, ulong start_offset, ulong end_offset ) {
2507 0 : ulong min_slot = ULONG_MAX;
2508 0 : long min_ts = LONG_MAX;
2509 :
2510 0 : for( ulong i=start_offset; i<end_offset; i++ ) {
2511 0 : min_slot = fd_ulong_min( min_slot, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].slot );
2512 0 : min_ts = fd_long_min ( min_ts, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].timestamp );
2513 0 : }
2514 :
2515 0 : jsonp_ulong ( gui->http, "reference_slot", min_slot );
2516 0 : jsonp_long_as_str( gui->http, "reference_ts", min_ts );
2517 :
2518 0 : jsonp_open_array( gui->http, "slot_delta" );
2519 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_ulong( gui->http, NULL, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].slot-min_slot );
2520 0 : jsonp_close_array( gui->http );
2521 0 : jsonp_open_array( gui->http, "shred_idx" );
2522 0 : for( ulong i=start_offset; i<end_offset; i++ ) {
2523 0 : if( FD_LIKELY( gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].shred_idx );
2524 0 : else jsonp_null ( gui->http, NULL );
2525 0 : }
2526 0 : jsonp_close_array( gui->http );
2527 0 : jsonp_open_array( gui->http, "event" );
2528 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_ulong( gui->http, NULL, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].event );
2529 0 : jsonp_close_array( gui->http );
2530 0 : jsonp_open_array( gui->http, "event_ts_delta" );
2531 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_long_as_str( gui->http, NULL, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].timestamp-min_ts );
2532 0 : jsonp_close_array( gui->http );
2533 0 : }
2534 :
2535 : void
2536 0 : fd_gui_printf_shreds_history( fd_gui_t * gui, ulong _slot ) {
2537 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
2538 0 : FD_TEST( slot );
2539 0 : ulong end_offset = slot->shreds.end_offset;
2540 0 : ulong start_offset = slot->shreds.start_offset;
2541 0 : FD_TEST( slot->shreds.end_offset > gui->shreds.history_tail-FD_GUI_SHREDS_HISTORY_SZ );
2542 :
2543 0 : long min_ts = LONG_MAX;
2544 0 : for( ulong i=start_offset; i<end_offset; i++ ) {
2545 0 : min_ts = fd_long_min ( min_ts, gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].timestamp );
2546 0 : }
2547 :
2548 0 : jsonp_ulong ( gui->http, "reference_slot", _slot );
2549 0 : jsonp_long_as_str( gui->http, "reference_ts", min_ts );
2550 :
2551 0 : jsonp_open_array( gui->http, "slot_delta" );
2552 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_ulong( gui->http, NULL, 0UL );
2553 0 : jsonp_close_array( gui->http );
2554 0 : jsonp_open_array( gui->http, "shred_idx" );
2555 0 : for( ulong i=start_offset; i<end_offset; i++ ) {
2556 0 : if( FD_LIKELY( gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].shred_idx );
2557 0 : else jsonp_null ( gui->http, NULL );
2558 0 : }
2559 0 : jsonp_close_array( gui->http );
2560 0 : jsonp_open_array( gui->http, "event" );
2561 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_ulong( gui->http, NULL, gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].event );
2562 0 : jsonp_close_array( gui->http );
2563 0 : jsonp_open_array( gui->http, "event_ts_delta" );
2564 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_long_as_str( gui->http, NULL, gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].timestamp-min_ts );
2565 0 : jsonp_close_array( gui->http );
2566 0 : }
2567 :
2568 : void
2569 0 : fd_gui_printf_shred_updates( fd_gui_t * gui ) {
2570 0 : jsonp_open_envelope( gui->http, "slot", "live_shreds" );
2571 0 : jsonp_open_object( gui->http, "value" );
2572 0 : fd_gui_printf_shreds_staged( gui, gui->shreds.staged_next_broadcast, gui->shreds.staged_tail );
2573 0 : jsonp_close_object( gui->http );
2574 0 : jsonp_close_envelope( gui->http );
2575 0 : }
2576 :
2577 : void
2578 0 : fd_gui_printf_shred_rebroadcast( fd_gui_t * gui, long after ) {
2579 0 : FD_TEST( gui->shreds.staged_next_broadcast!=ULONG_MAX );
2580 :
2581 0 : ulong _start_offset = gui->shreds.staged_next_broadcast;
2582 0 : for( ulong i=gui->shreds.staged_head; i<gui->shreds.staged_next_broadcast; i++ ) {
2583 0 : if( FD_LIKELY( gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].timestamp<after ) ) continue;
2584 0 : _start_offset = i;
2585 0 : break;
2586 0 : }
2587 :
2588 0 : jsonp_open_envelope( gui->http, "slot", "live_shreds" );
2589 0 : jsonp_open_object( gui->http, "value" );
2590 0 : fd_gui_printf_shreds_staged( gui, _start_offset, gui->shreds.staged_next_broadcast );
2591 0 : jsonp_close_object( gui->http );
2592 0 : jsonp_close_envelope( gui->http );
2593 0 : }
2594 :
2595 : void
2596 : fd_gui_printf_slot_query_shreds( fd_gui_t * gui,
2597 : ulong _slot,
2598 0 : ulong id ) {
2599 0 : jsonp_open_envelope( gui->http, "slot", "query_shreds" );
2600 0 : jsonp_ulong( gui->http, "id", id );
2601 0 : jsonp_open_object( gui->http, "value" );
2602 0 : fd_gui_printf_shreds_history( gui, _slot );
2603 0 : jsonp_close_object( gui->http );
2604 0 : jsonp_close_envelope( gui->http );
2605 0 : }
|