Line data Source code
1 : #include "fd_gui_printf.h"
2 : #include "fd_gui_config_parse.h"
3 :
4 : #include "../bundle/fd_bundle_tile.h"
5 : #include "../diag/fd_diag_tile.h"
6 : #include "../../waltz/http/fd_http_server_private.h"
7 : #include "../../ballet/utf8/fd_utf8.h"
8 : #include "../../disco/fd_txn_m.h"
9 : #include "../../disco/metrics/fd_metrics.h"
10 : #include "../../disco/topo/fd_topob.h"
11 :
12 : static void
13 0 : jsonp_strip_trailing_comma( fd_http_server_t * http ) {
14 0 : if( FD_LIKELY( !http->stage_err &&
15 0 : http->stage_len>=1UL &&
16 0 : http->oring[ (http->stage_off%http->oring_sz)+http->stage_len-1UL ]==(uchar)',' ) ) {
17 0 : http->stage_len--;
18 0 : }
19 0 : }
20 :
21 : static void
22 : jsonp_open_object( fd_http_server_t * http,
23 0 : char const * key ) {
24 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":{", key );
25 0 : else fd_http_server_printf( http, "{" );
26 0 : }
27 :
28 : static void
29 0 : jsonp_close_object( fd_http_server_t * http ) {
30 0 : jsonp_strip_trailing_comma( http );
31 0 : fd_http_server_printf( http, "}," );
32 0 : }
33 :
34 : static void
35 : jsonp_open_array( fd_http_server_t * http,
36 0 : char const * key ) {
37 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":[", key );
38 0 : else fd_http_server_printf( http, "[" );
39 0 : }
40 :
41 : static void
42 0 : jsonp_close_array( fd_http_server_t * http ) {
43 0 : jsonp_strip_trailing_comma( http );
44 0 : fd_http_server_printf( http, "]," );
45 0 : }
46 :
47 : static void
48 : jsonp_ulong( fd_http_server_t * http,
49 : char const * key,
50 0 : ulong value ) {
51 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%lu,", key, value );
52 0 : else fd_http_server_printf( http, "%lu,", value );
53 0 : }
54 :
55 : static void
56 : jsonp_long( fd_http_server_t * http,
57 : char const * key,
58 0 : long value ) {
59 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%ld,", key, value );
60 0 : else fd_http_server_printf( http, "%ld,", value );
61 0 : }
62 :
63 : static void
64 : jsonp_double( fd_http_server_t * http,
65 : char const * key,
66 0 : double value ) {
67 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%.2f,", key, value );
68 0 : else fd_http_server_printf( http, "%.2f,", value );
69 0 : }
70 :
71 : static void
72 : jsonp_ulong_as_str( fd_http_server_t * http,
73 : char const * key,
74 0 : ulong value ) {
75 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":\"%lu\",", key, value );
76 0 : else fd_http_server_printf( http, "\"%lu\",", value );
77 0 : }
78 :
79 : static void
80 : jsonp_long_as_str( fd_http_server_t * http,
81 : char const * key,
82 0 : long value ) {
83 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":\"%ld\",", key, value );
84 0 : else fd_http_server_printf( http, "\"%ld\",", value );
85 0 : }
86 :
87 : static void
88 : jsonp_sanitize_str( fd_http_server_t * http,
89 0 : ulong start_len ) {
90 : /* escape quotemark, reverse solidus, and control chars U+0000 through U+001F
91 : just replace with a space */
92 0 : uchar * data = http->oring;
93 0 : for( ulong i=start_len; i<http->stage_len; i++ ) {
94 0 : if( FD_UNLIKELY( data[ (http->stage_off%http->oring_sz)+i ] < 0x20 ||
95 0 : data[ (http->stage_off%http->oring_sz)+i ] == '"' ||
96 0 : data[ (http->stage_off%http->oring_sz)+i ] == '\\' ) ) {
97 0 : data[ (http->stage_off%http->oring_sz)+i ] = ' ';
98 0 : }
99 0 : }
100 0 : }
101 :
102 : static void
103 : jsonp_string( fd_http_server_t * http,
104 : char const * key,
105 0 : char const * value ) {
106 0 : char * val = (void *)value;
107 0 : if( FD_LIKELY( value ) ) {
108 0 : if( FD_UNLIKELY( !fd_utf8_verify( value, strlen( value ) ) )) {
109 0 : val = NULL;
110 0 : }
111 0 : }
112 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":", key );
113 0 : if( FD_LIKELY( val ) ) {
114 0 : fd_http_server_printf( http, "\"" );
115 0 : ulong start_len = http->stage_len;
116 0 : fd_http_server_printf( http, "%s", val );
117 0 : jsonp_sanitize_str( http, start_len );
118 0 : fd_http_server_printf( http, "\"," );
119 0 : } else {
120 0 : fd_http_server_printf( http, "null," );
121 0 : }
122 0 : }
123 :
124 : static void
125 : jsonp_bool( fd_http_server_t * http,
126 : char const * key,
127 0 : int value ) {
128 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%s,", key, value ? "true" : "false" );
129 0 : else fd_http_server_printf( http, "%s,", value ? "true" : "false" );
130 0 : }
131 :
132 : static void
133 : jsonp_null( fd_http_server_t * http,
134 0 : char const * key ) {
135 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\": null,", key );
136 0 : else fd_http_server_printf( http, "null," );
137 0 : }
138 :
139 : static void
140 : jsonp_open_envelope( fd_http_server_t * http,
141 : char const * topic,
142 0 : char const * key ) {
143 0 : jsonp_open_object( http, NULL );
144 0 : jsonp_string( http, "topic", topic );
145 0 : jsonp_string( http, "key", key );
146 0 : }
147 :
148 : static void
149 0 : jsonp_close_envelope( fd_http_server_t * http ) {
150 0 : jsonp_close_object( http );
151 0 : jsonp_strip_trailing_comma( http );
152 0 : }
153 :
154 : void
155 : fd_gui_printf_open_query_response_envelope( fd_http_server_t * http,
156 : char const * topic,
157 : char const * key,
158 0 : ulong id ) {
159 0 : jsonp_open_object( http, NULL );
160 0 : jsonp_string( http, "topic", topic );
161 0 : jsonp_string( http, "key", key );
162 0 : jsonp_ulong( http, "id", id );
163 0 : }
164 :
165 : void
166 0 : fd_gui_printf_close_query_response_envelope( fd_http_server_t * http ) {
167 0 : jsonp_close_object( http );
168 0 : jsonp_strip_trailing_comma( http );
169 0 : }
170 :
171 : void
172 : fd_gui_printf_null_query_response( fd_http_server_t * http,
173 : char const * topic,
174 : char const * key,
175 0 : ulong id ) {
176 0 : fd_gui_printf_open_query_response_envelope( http, topic, key, id );
177 0 : jsonp_null( http, "value" );
178 0 : fd_gui_printf_close_query_response_envelope( http );
179 0 : }
180 :
181 : void
182 0 : fd_gui_printf_version( fd_gui_t * gui ) {
183 0 : jsonp_open_envelope( gui->http, "summary", "version" );
184 0 : jsonp_string( gui->http, "value", gui->summary.version );
185 0 : jsonp_close_envelope( gui->http );
186 0 : }
187 :
188 : void
189 0 : fd_gui_printf_cluster( fd_gui_t * gui ) {
190 0 : jsonp_open_envelope( gui->http, "summary", "cluster" );
191 0 : jsonp_string( gui->http, "value", gui->summary.cluster );
192 0 : jsonp_close_envelope( gui->http );
193 0 : }
194 :
195 : void
196 0 : fd_gui_printf_commit_hash( fd_gui_t * gui ) {
197 0 : jsonp_open_envelope( gui->http, "summary", "commit_hash" );
198 0 : jsonp_string( gui->http, "value", fd_commit_ref_cstr );
199 0 : jsonp_close_envelope( gui->http );
200 0 : }
201 :
202 : void
203 0 : fd_gui_printf_identity_key( fd_gui_t * gui ) {
204 0 : jsonp_open_envelope( gui->http, "summary", "identity_key" );
205 0 : jsonp_string( gui->http, "value", gui->summary.identity_key_base58 );
206 0 : jsonp_close_envelope( gui->http );
207 0 : }
208 :
209 : void
210 0 : fd_gui_printf_vote_key( fd_gui_t * gui ) {
211 0 : jsonp_open_envelope( gui->http, "summary", "vote_key" );
212 0 : if( FD_LIKELY( gui->summary.has_vote_key ) ) jsonp_string( gui->http, "value", gui->summary.vote_key_base58 );
213 0 : else jsonp_null( gui->http, "value" );
214 0 : jsonp_close_envelope( gui->http );
215 0 : }
216 :
217 : void
218 0 : fd_gui_printf_startup_time_nanos( fd_gui_t * gui ) {
219 0 : jsonp_open_envelope( gui->http, "summary", "startup_time_nanos" );
220 0 : jsonp_long_as_str( gui->http, "value", gui->summary.startup_time_nanos );
221 0 : jsonp_close_envelope( gui->http );
222 0 : }
223 :
224 : void
225 0 : fd_gui_printf_server_time_nanos( fd_gui_t * gui, long now ) {
226 0 : jsonp_open_envelope( gui->http, "summary", "server_time_nanos" );
227 0 : jsonp_long_as_str( gui->http, "value", now );
228 0 : jsonp_close_envelope( gui->http );
229 0 : }
230 :
231 : void
232 0 : fd_gui_printf_vote_distance( fd_gui_t * gui ) {
233 0 : jsonp_open_envelope( gui->http, "summary", "vote_distance" );
234 0 : jsonp_ulong( gui->http, "value", gui->summary.vote_distance );
235 0 : jsonp_close_envelope( gui->http );
236 0 : }
237 :
238 : void
239 0 : fd_gui_printf_repair_slot( fd_gui_t * gui ) {
240 0 : jsonp_open_envelope( gui->http, "summary", "repair_slot" );
241 0 : if( FD_LIKELY( gui->summary.slot_repair!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_repair );
242 0 : else jsonp_null ( gui->http, "value" );
243 0 : jsonp_close_envelope( gui->http );
244 0 : }
245 :
246 : void
247 0 : fd_gui_peers_printf_vote_slot( fd_gui_peers_ctx_t * peers ) {
248 0 : jsonp_open_envelope( peers->http, "summary", "vote_slot" );
249 0 : if( FD_LIKELY( peers->slot_voted!=ULONG_MAX ) ) jsonp_ulong( peers->http, "value", peers->slot_voted );
250 0 : else jsonp_null ( peers->http, "value" );
251 0 : jsonp_close_envelope( peers->http );
252 0 : }
253 :
254 : void
255 0 : fd_gui_printf_turbine_slot( fd_gui_t * gui ) {
256 0 : jsonp_open_envelope( gui->http, "summary", "turbine_slot" );
257 0 : if( FD_LIKELY( gui->summary.slot_turbine!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_turbine );
258 0 : else jsonp_null ( gui->http, "value" );
259 0 : jsonp_close_envelope( gui->http );
260 0 : }
261 :
262 : void
263 0 : fd_gui_printf_reset_slot( fd_gui_t * gui ) {
264 0 : jsonp_open_envelope( gui->http, "summary", "reset_slot" );
265 0 : if( FD_LIKELY( gui->summary.slot_reset!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_reset );
266 0 : else jsonp_null ( gui->http, "value" );
267 0 : jsonp_close_envelope( gui->http );
268 0 : }
269 :
270 : void
271 0 : fd_gui_printf_storage_slot( fd_gui_t * gui ) {
272 0 : jsonp_open_envelope( gui->http, "summary", "storage_slot" );
273 0 : if( FD_LIKELY( gui->summary.slot_storage!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_storage );
274 0 : else jsonp_null ( gui->http, "value" );
275 0 : jsonp_close_envelope( gui->http );
276 0 : }
277 :
278 : void
279 0 : fd_gui_printf_active_fork_cnt( fd_gui_t * gui ) {
280 0 : jsonp_open_envelope( gui->http, "summary", "active_fork_count" );
281 0 : if( FD_LIKELY( gui->summary.active_fork_cnt!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.active_fork_cnt );
282 0 : else jsonp_null ( gui->http, "value" );
283 0 : jsonp_close_envelope( gui->http );
284 0 : }
285 :
286 : void
287 0 : fd_gui_printf_slot_caught_up( fd_gui_t * gui ) {
288 0 : jsonp_open_envelope( gui->http, "summary", "slot_caught_up" );
289 0 : if( FD_LIKELY( gui->summary.slot_caught_up!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_caught_up );
290 0 : else jsonp_null ( gui->http, "value" );
291 0 : jsonp_close_envelope( gui->http );
292 0 : }
293 :
294 : void
295 0 : fd_gui_printf_catch_up_history( fd_gui_t * gui ) {
296 0 : jsonp_open_envelope( gui->http, "summary", "catch_up_history" );
297 0 : jsonp_open_object( gui->http, "value" );
298 0 : jsonp_open_array( gui->http, "turbine" );
299 0 : for( ulong i=0UL; i<gui->summary.catch_up_turbine_sz; i+=2 ) {
300 0 : for( ulong j=gui->summary.catch_up_turbine[ i ]; j<=gui->summary.catch_up_turbine[ i+1UL ]; j++ ) {
301 0 : jsonp_ulong( gui->http, NULL, j );
302 0 : }
303 0 : }
304 0 : jsonp_close_array( gui->http );
305 0 : jsonp_open_array( gui->http, "repair" );
306 0 : for( ulong i=0UL; i<gui->summary.catch_up_repair_sz; i+=2 ) {
307 0 : for( ulong j=gui->summary.catch_up_repair[ i ]; j<=gui->summary.catch_up_repair[ i+1UL ]; j++ ) {
308 0 : jsonp_ulong( gui->http, NULL, j );
309 0 : }
310 0 : }
311 0 : jsonp_close_array( gui->http );
312 :
313 0 : if( FD_LIKELY( gui->summary.boot_progress.phase==FD_GUI_BOOT_PROGRESS_TYPE_CATCHING_UP ) ) {
314 0 : ulong min_slot = ULONG_MAX;
315 0 : long min_ts = LONG_MAX;
316 :
317 0 : #define SHREDS_REV_ITER( age_ns, code_staged, code_archive ) \
318 0 : do { \
319 0 : if( FD_UNLIKELY( gui->summary.boot_progress.catching_up_time_nanos==0L ) ) break; \
320 0 : for( ulong i=gui->shreds.staged_tail; i>gui->shreds.staged_head; i-- ) { \
321 0 : fd_gui_slot_staged_shred_event_t * event = &gui->shreds.staged[ (i-1UL) % FD_GUI_SHREDS_STAGING_SZ ]; \
322 0 : if( FD_UNLIKELY( event->timestamp < gui->summary.boot_progress.catching_up_time_nanos - age_ns ) ) break; \
323 0 : do { code_staged } while(0); \
324 0 : } \
325 0 : fd_gui_slot_t * s = fd_gui_get_slot( gui, gui->shreds.history_slot ); \
326 0 : while( s \
327 0 : && s->shreds.start_offset!=ULONG_MAX \
328 0 : && s->shreds.end_offset!=ULONG_MAX \
329 0 : && s->shreds.end_offset>s->shreds.start_offset \
330 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 ) { \
331 0 : for( ulong i=s->shreds.end_offset; i>s->shreds.start_offset; i-- ) { \
332 0 : fd_gui_slot_history_shred_event_t * event = &gui->shreds.history[ (i-1UL) % FD_GUI_SHREDS_HISTORY_SZ ]; (void)event; \
333 0 : do { code_archive } while (0); \
334 0 : } \
335 0 : s = fd_gui_get_slot( gui, s->parent_slot ); \
336 0 : } \
337 0 : } while(0);
338 :
339 0 : SHREDS_REV_ITER(
340 0 : 15000000000,
341 0 : {
342 0 : min_slot = fd_ulong_min( min_slot, event->slot );
343 0 : min_ts = fd_long_min( min_ts, event->timestamp );
344 0 : },
345 0 : {
346 0 : min_slot = fd_ulong_min( min_slot, s->slot );
347 0 : min_ts = fd_long_min( min_ts, event->timestamp );
348 0 : }
349 0 : )
350 :
351 0 : jsonp_open_object( gui->http, "shreds" );
352 0 : jsonp_ulong ( gui->http, "reference_slot", min_slot );
353 0 : jsonp_long_as_str( gui->http, "reference_ts", min_ts );
354 :
355 0 : jsonp_open_array( gui->http, "slot_delta" );
356 0 : SHREDS_REV_ITER(
357 0 : 15000000000L,
358 0 : { jsonp_ulong( gui->http, NULL, event->slot-min_slot ); },
359 0 : { jsonp_ulong( gui->http, NULL, s->slot-min_slot ); }
360 0 : )
361 0 : jsonp_close_array( gui->http );
362 0 : jsonp_open_array( gui->http, "shred_idx" );
363 0 : SHREDS_REV_ITER(
364 0 : 15000000000L,
365 0 : {
366 0 : if( FD_LIKELY( event->shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, event->shred_idx );
367 0 : else jsonp_null ( gui->http, NULL );
368 0 : },
369 0 : {
370 0 : if( FD_LIKELY( event->shred_idx!=USHORT_MAX ) ) jsonp_ulong( gui->http, NULL, event->shred_idx );
371 0 : else jsonp_null ( gui->http, NULL );
372 0 : }
373 0 : )
374 0 : jsonp_close_array( gui->http );
375 0 : jsonp_open_array( gui->http, "event" );
376 0 : SHREDS_REV_ITER(
377 0 : 15000000000L,
378 0 : { jsonp_ulong( gui->http, NULL, event->event ); },
379 0 : { jsonp_ulong( gui->http, NULL, event->event ); }
380 0 : )
381 0 : jsonp_close_array( gui->http );
382 0 : jsonp_open_array( gui->http, "event_ts_delta" );
383 0 : SHREDS_REV_ITER(
384 0 : 15000000000L,
385 0 : { jsonp_long_as_str( gui->http, NULL, event->timestamp-min_ts ); },
386 0 : { jsonp_long_as_str( gui->http, NULL, event->timestamp-min_ts ); }
387 0 : )
388 0 : jsonp_close_array( gui->http );
389 0 : jsonp_close_object( gui->http );
390 0 : } else {
391 0 : jsonp_null( gui->http, "shreds" );
392 0 : }
393 :
394 0 : jsonp_close_object( gui->http );
395 0 : jsonp_close_envelope( gui->http );
396 0 : }
397 :
398 : void
399 0 : fd_gui_printf_vote_state( fd_gui_t * gui ) {
400 0 : jsonp_open_envelope( gui->http, "summary", "vote_state" );
401 0 : switch( gui->summary.vote_state ) {
402 0 : case FD_GUI_VOTE_STATE_NON_VOTING:
403 0 : jsonp_string( gui->http, "value", "non-voting" );
404 0 : break;
405 0 : case FD_GUI_VOTE_STATE_VOTING:
406 0 : jsonp_string( gui->http, "value", "voting" );
407 0 : break;
408 0 : case FD_GUI_VOTE_STATE_DELINQUENT:
409 0 : jsonp_string( gui->http, "value", "delinquent" );
410 0 : break;
411 0 : default:
412 0 : FD_LOG_ERR(( "unknown vote state %d", gui->summary.vote_state ));
413 0 : }
414 0 : jsonp_close_envelope( gui->http );
415 0 : }
416 :
417 : void
418 0 : fd_gui_printf_skipped_history( fd_gui_t * gui, ulong epoch_idx ) {
419 0 : jsonp_open_envelope( gui->http, "slot", "skipped_history" );
420 0 : jsonp_open_array( gui->http, "value" );
421 0 : ulong start_slot = gui->epoch.epochs[ epoch_idx ].start_slot;
422 0 : ulong end_slot = gui->epoch.epochs[ epoch_idx ].end_slot;
423 0 : for( ulong s=start_slot; s<fd_ulong_min( end_slot, start_slot+FD_GUI_SLOTS_CNT ); s++ ) {
424 0 : if( FD_LIKELY( gui->summary.slot_completed==ULONG_MAX ) ) break;
425 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, s );
426 :
427 0 : if( FD_UNLIKELY( !slot ) ) continue;
428 0 : if( FD_UNLIKELY( slot->mine && slot->skipped ) ) jsonp_ulong( gui->http, NULL, slot->slot );
429 0 : }
430 0 : jsonp_close_array( gui->http );
431 0 : jsonp_close_envelope( gui->http );
432 0 : }
433 :
434 : void
435 0 : fd_gui_printf_skipped_history_cluster( fd_gui_t * gui, ulong epoch_idx ) {
436 0 : jsonp_open_envelope( gui->http, "slot", "skipped_history_cluster" );
437 0 : jsonp_open_array( gui->http, "value" );
438 0 : ulong start_slot = gui->epoch.epochs[ epoch_idx ].start_slot;
439 0 : ulong end_slot = gui->epoch.epochs[ epoch_idx ].end_slot;
440 0 : for( ulong s=start_slot; s<fd_ulong_min( end_slot, start_slot+FD_GUI_SLOTS_CNT ); s++ ) {
441 0 : if( FD_LIKELY( gui->summary.slot_completed==ULONG_MAX ) ) break;
442 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, s );
443 :
444 0 : if( FD_UNLIKELY( !slot ) ) continue;
445 0 : if( FD_UNLIKELY( slot->skipped ) ) jsonp_ulong( gui->http, NULL, slot->slot );
446 0 : }
447 0 : jsonp_close_array( gui->http );
448 0 : jsonp_close_envelope( gui->http );
449 0 : }
450 :
451 : /* TODO: deprecated */
452 : void
453 0 : fd_gui_printf_vote_latency_history( fd_gui_t * gui ) {
454 0 : jsonp_open_envelope( gui->http, "slot", "vote_latency_history" );
455 0 : jsonp_open_array( gui->http, "value" );
456 0 : FD_TEST( gui->summary.late_votes_sz % 2UL == 0UL );
457 0 : for( ulong i=0UL; i<gui->summary.late_votes_sz; i++ ) jsonp_ulong( gui->http, NULL, gui->summary.late_votes[ i ] );
458 0 : jsonp_close_array( gui->http );
459 0 : jsonp_close_envelope( gui->http );
460 0 : }
461 :
462 : void
463 0 : fd_gui_printf_late_votes_history( fd_gui_t * gui ) {
464 0 : jsonp_open_envelope( gui->http, "slot", "late_votes_history" );
465 0 : jsonp_open_object( gui->http, "value" );
466 0 : jsonp_open_array( gui->http, "slot" );
467 0 : for( ulong i=0UL; i<gui->summary.late_votes_sz; i++ ) jsonp_ulong( gui->http, NULL, gui->summary.late_votes[ i ] );
468 0 : jsonp_close_array( gui->http );
469 0 : jsonp_open_array( gui->http, "latency" );
470 0 : for( long i=0UL; i<(long)gui->summary.late_votes_sz-1L; i+=2L ) {
471 0 : FD_TEST( (ulong)i+1<gui->summary.late_votes_sz );
472 0 : ulong s = gui->summary.late_votes[ i ];
473 0 : ulong s2 = gui->summary.late_votes[ i + 1 ];
474 0 : for( ulong j=s; j<=fd_ulong_min( s2, s+FD_GUI_SLOTS_CNT ); j++ ) {
475 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, j );
476 0 : if( FD_UNLIKELY( slot && slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, NULL, slot->vote_latency );
477 0 : else jsonp_null( gui->http, NULL );
478 0 : }
479 0 : }
480 0 : jsonp_close_array( gui->http );
481 0 : jsonp_close_object( gui->http );
482 0 : jsonp_close_envelope( gui->http );
483 0 : }
484 :
485 : void
486 0 : fd_gui_printf_tps_history( fd_gui_t * gui ) {
487 0 : jsonp_open_envelope( gui->http, "summary", "tps_history" );
488 0 : jsonp_open_array( gui->http, "value" );
489 :
490 0 : for( ulong i=0UL; i<FD_GUI_TPS_HISTORY_SAMPLE_CNT; i++ ) {
491 0 : ulong idx = (gui->summary.estimated_tps_history_idx+i) % FD_GUI_TPS_HISTORY_SAMPLE_CNT;
492 0 : ulong vote_cnt = gui->summary.estimated_tps_history[ idx ].vote_failed
493 0 : + gui->summary.estimated_tps_history[ idx ].vote_success;
494 0 : ulong total_cnt = vote_cnt
495 0 : + gui->summary.estimated_tps_history[ idx ].nonvote_success
496 0 : + gui->summary.estimated_tps_history[ idx ].nonvote_failed;
497 0 : jsonp_open_array( gui->http, NULL );
498 0 : jsonp_double( gui->http, NULL, (double)total_cnt/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
499 0 : jsonp_double( gui->http, NULL, (double)vote_cnt/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
500 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ].nonvote_success/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
501 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ].nonvote_failed/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
502 0 : jsonp_close_array( gui->http );
503 0 : }
504 :
505 0 : jsonp_close_array( gui->http );
506 0 : jsonp_close_envelope( gui->http );
507 0 : }
508 :
509 : void
510 0 : fd_gui_printf_block_engine( fd_gui_t * gui ) {
511 0 : jsonp_open_envelope( gui->http, "block_engine", "update" );
512 0 : jsonp_open_object( gui->http, "value" );
513 0 : jsonp_string( gui->http, "name", gui->block_engine.name );
514 0 : jsonp_string( gui->http, "url", gui->block_engine.url );
515 0 : jsonp_string( gui->http, "ip", gui->block_engine.ip_cstr );
516 0 : if( FD_LIKELY( gui->block_engine.status==FD_BUNDLE_STATE_CONNECTING ) ) jsonp_string( gui->http, "status", "connecting" );
517 0 : else if( FD_LIKELY( gui->block_engine.status==FD_BUNDLE_STATE_CONNECTED ) ) jsonp_string( gui->http, "status", "connected" );
518 0 : else if( FD_LIKELY( gui->block_engine.status==FD_BUNDLE_STATE_SLEEPING ) ) jsonp_string( gui->http, "status", "sleeping" );
519 0 : else jsonp_string( gui->http, "status", "disconnected" );
520 0 : jsonp_close_object( gui->http );
521 0 : jsonp_close_envelope( gui->http );
522 0 : }
523 :
524 : void
525 0 : fd_gui_printf_tiles( fd_gui_t * gui ) {
526 0 : jsonp_open_envelope( gui->http, "summary", "tiles" );
527 0 : jsonp_open_array( gui->http, "value" );
528 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
529 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ gui->summary.tile[ i ] ];
530 :
531 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
532 : /* bench tiles not reported */
533 0 : continue;
534 0 : }
535 :
536 0 : jsonp_open_object( gui->http, NULL );
537 0 : jsonp_string( gui->http, "kind", tile->name );
538 0 : jsonp_ulong( gui->http, "kind_id", tile->kind_id );
539 0 : jsonp_ulong( gui->http, "pid", fd_metrics_tile( tile->metrics )[ MIDX( GAUGE, TILE, PID ) ] );
540 0 : jsonp_close_object( gui->http );
541 0 : }
542 0 : jsonp_close_array( gui->http );
543 0 : jsonp_close_envelope( gui->http );
544 0 : }
545 :
546 : void
547 0 : fd_gui_printf_schedule_strategy( fd_gui_t * gui ) {
548 0 : jsonp_open_envelope( gui->http, "summary", "schedule_strategy" );
549 0 : char mode[10];
550 0 : switch (gui->summary.schedule_strategy) {
551 0 : case 0: strncpy( mode, "perf", sizeof(mode) ); break;
552 0 : case 1: strncpy( mode, "balanced", sizeof(mode) ); break;
553 0 : case 2: strncpy( mode, "revenue", sizeof(mode) ); break;
554 0 : default: FD_LOG_ERR(("unexpected schedule_strategy %d", gui->summary.schedule_strategy));
555 0 : }
556 0 : mode[ sizeof(mode) - 1] = '\0';
557 0 : jsonp_string( gui->http, "value", mode );
558 0 : jsonp_close_envelope( gui->http );
559 0 : }
560 :
561 : void
562 0 : fd_gui_printf_identity_balance( fd_gui_t * gui ) {
563 0 : jsonp_open_envelope( gui->http, "summary", "identity_balance" );
564 0 : jsonp_ulong_as_str( gui->http, "value", gui->summary.identity_account_balance );
565 0 : jsonp_close_envelope( gui->http );
566 0 : }
567 :
568 : void
569 0 : fd_gui_printf_vote_balance( fd_gui_t * gui ) {
570 0 : jsonp_open_envelope( gui->http, "summary", "vote_balance" );
571 0 : jsonp_ulong_as_str( gui->http, "value", gui->summary.vote_account_balance );
572 0 : jsonp_close_envelope( gui->http );
573 0 : }
574 :
575 : void
576 0 : fd_gui_printf_estimated_slot_duration_nanos( fd_gui_t * gui ) {
577 0 : jsonp_open_envelope( gui->http, "summary", "estimated_slot_duration_nanos" );
578 0 : jsonp_ulong( gui->http, "value", gui->summary.estimated_slot_duration_nanos );
579 0 : jsonp_close_envelope( gui->http );
580 0 : }
581 :
582 :
583 : void
584 0 : fd_gui_printf_root_slot( fd_gui_t * gui ) {
585 0 : jsonp_open_envelope( gui->http, "summary", "root_slot" );
586 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_rooted!=ULONG_MAX, gui->summary.slot_rooted, 0UL ) );
587 0 : jsonp_close_envelope( gui->http );
588 0 : }
589 :
590 : void
591 0 : fd_gui_printf_optimistically_confirmed_slot( fd_gui_t * gui ) {
592 0 : jsonp_open_envelope( gui->http, "summary", "optimistically_confirmed_slot" );
593 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_optimistically_confirmed!=ULONG_MAX, gui->summary.slot_optimistically_confirmed, 0UL ) );
594 0 : jsonp_close_envelope( gui->http );
595 0 : }
596 :
597 : void
598 0 : fd_gui_printf_completed_slot( fd_gui_t * gui ) {
599 0 : jsonp_open_envelope( gui->http, "summary", "completed_slot" );
600 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_completed!=ULONG_MAX, gui->summary.slot_completed, 0UL ) );
601 0 : jsonp_close_envelope( gui->http );
602 0 : }
603 :
604 : void
605 0 : fd_gui_printf_estimated_slot( fd_gui_t * gui ) {
606 0 : jsonp_open_envelope( gui->http, "summary", "estimated_slot" );
607 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_estimated!=ULONG_MAX, gui->summary.slot_estimated, 0UL ) );
608 0 : jsonp_close_envelope( gui->http );
609 0 : }
610 :
611 : void
612 : fd_gui_printf_skip_rate( fd_gui_t * gui,
613 0 : ulong epoch_idx ) {
614 0 : jsonp_open_envelope( gui->http, "summary", "skip_rate" );
615 0 : jsonp_open_object( gui->http, "value" );
616 0 : jsonp_ulong( gui->http, "epoch", gui->epoch.epochs[ epoch_idx ].epoch );
617 0 : fd_http_server_printf( gui->http, "\"skip_rate\":%.7f,", !!gui->epoch.epochs[ epoch_idx ].my_total_slots ? (double)gui->epoch.epochs[ epoch_idx ].my_skipped_slots/(double)gui->epoch.epochs[ epoch_idx ].my_total_slots : 0.0 );
618 0 : jsonp_close_object( gui->http );
619 0 : jsonp_close_envelope( gui->http );
620 0 : }
621 :
622 : void
623 : fd_gui_printf_epoch( fd_gui_t * gui,
624 0 : ulong epoch_idx ) {
625 0 : jsonp_open_envelope( gui->http, "epoch", "new" );
626 0 : jsonp_open_object( gui->http, "value" );
627 0 : jsonp_ulong( gui->http, "epoch", gui->epoch.epochs[ epoch_idx ].epoch );
628 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 );
629 0 : else jsonp_null( gui->http, "start_time_nanos" );
630 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 );
631 0 : else jsonp_null( gui->http, "end_time_nanos" );
632 0 : jsonp_ulong( gui->http, "start_slot", gui->epoch.epochs[ epoch_idx ].start_slot );
633 0 : jsonp_ulong( gui->http, "end_slot", gui->epoch.epochs[ epoch_idx ].end_slot );
634 0 : jsonp_ulong_as_str( gui->http, "excluded_stake_lamports", 0UL );
635 0 : jsonp_open_array( gui->http, "staked_pubkeys" );
636 0 : fd_epoch_leaders_t * lsched = gui->epoch.epochs[epoch_idx].lsched;
637 0 : for( ulong i=0UL; i<lsched->pub_cnt; i++ ) {
638 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
639 0 : fd_base58_encode_32( lsched->pub[ i ].uc, NULL, identity_base58 );
640 0 : jsonp_string( gui->http, NULL, identity_base58 );
641 0 : }
642 0 : jsonp_close_array( gui->http );
643 :
644 0 : jsonp_open_array( gui->http, "staked_lamports" );
645 0 : fd_vote_stake_weight_t * stakes = gui->epoch.epochs[epoch_idx].stakes;
646 0 : for( ulong i=0UL; i<lsched->pub_cnt; i++ ) jsonp_ulong_as_str( gui->http, NULL, stakes[ i ].stake );
647 0 : jsonp_close_array( gui->http );
648 :
649 0 : jsonp_open_array( gui->http, "leader_slots" );
650 0 : for( ulong i = 0; i < lsched->sched_cnt; i++ ) jsonp_ulong( gui->http, NULL, lsched->sched[ i ] );
651 0 : jsonp_close_array( gui->http );
652 0 : jsonp_close_object( gui->http );
653 0 : jsonp_close_envelope( gui->http );
654 0 : }
655 :
656 : static void
657 : fd_gui_printf_waterfall( fd_gui_t * gui,
658 : fd_gui_txn_waterfall_t const * prev,
659 0 : fd_gui_txn_waterfall_t const * cur ) {
660 0 : jsonp_open_object( gui->http, "waterfall" );
661 0 : jsonp_open_object( gui->http, "in" );
662 0 : jsonp_ulong( gui->http, "pack_cranked", cur->in.pack_cranked - prev->in.pack_cranked );
663 0 : jsonp_ulong( gui->http, "pack_retained", prev->out.pack_retained );
664 0 : jsonp_ulong( gui->http, "resolv_retained", prev->out.resolv_retained );
665 0 : jsonp_ulong( gui->http, "quic", cur->in.quic - prev->in.quic );
666 0 : jsonp_ulong( gui->http, "udp", cur->in.udp - prev->in.udp );
667 0 : jsonp_ulong( gui->http, "gossip", cur->in.gossip - prev->in.gossip );
668 0 : jsonp_ulong( gui->http, "block_engine", cur->in.block_engine - prev->in.block_engine );
669 0 : jsonp_close_object( gui->http );
670 :
671 0 : jsonp_open_object( gui->http, "out" );
672 0 : jsonp_ulong( gui->http, "net_overrun", cur->out.net_overrun - prev->out.net_overrun );
673 0 : jsonp_ulong( gui->http, "quic_overrun", cur->out.quic_overrun - prev->out.quic_overrun );
674 0 : jsonp_ulong( gui->http, "quic_frag_drop", cur->out.quic_frag_drop - prev->out.quic_frag_drop );
675 0 : jsonp_ulong( gui->http, "quic_abandoned", cur->out.quic_abandoned - prev->out.quic_abandoned );
676 0 : jsonp_ulong( gui->http, "tpu_quic_invalid", cur->out.tpu_quic_invalid - prev->out.tpu_quic_invalid );
677 0 : jsonp_ulong( gui->http, "tpu_udp_invalid", cur->out.tpu_udp_invalid - prev->out.tpu_udp_invalid );
678 0 : jsonp_ulong( gui->http, "verify_overrun", cur->out.verify_overrun - prev->out.verify_overrun );
679 0 : jsonp_ulong( gui->http, "verify_parse", cur->out.verify_parse - prev->out.verify_parse );
680 0 : jsonp_ulong( gui->http, "verify_failed", cur->out.verify_failed - prev->out.verify_failed );
681 0 : jsonp_ulong( gui->http, "verify_duplicate", cur->out.verify_duplicate - prev->out.verify_duplicate );
682 0 : jsonp_ulong( gui->http, "dedup_duplicate", cur->out.dedup_duplicate - prev->out.dedup_duplicate );
683 0 : jsonp_ulong( gui->http, "resolv_lut_failed", cur->out.resolv_lut_failed - prev->out.resolv_lut_failed );
684 0 : jsonp_ulong( gui->http, "resolv_expired", cur->out.resolv_expired - prev->out.resolv_expired );
685 0 : jsonp_ulong( gui->http, "resolv_ancient", cur->out.resolv_ancient - prev->out.resolv_ancient );
686 0 : jsonp_ulong( gui->http, "resolv_no_ledger", cur->out.resolv_no_ledger - prev->out.resolv_no_ledger );
687 0 : jsonp_ulong( gui->http, "resolv_retained", cur->out.resolv_retained );
688 0 : jsonp_ulong( gui->http, "pack_invalid", cur->out.pack_invalid - prev->out.pack_invalid );
689 0 : jsonp_ulong( gui->http, "pack_invalid_bundle", cur->out.pack_invalid_bundle - prev->out.pack_invalid_bundle );
690 0 : jsonp_ulong( gui->http, "pack_expired", cur->out.pack_expired - prev->out.pack_expired );
691 0 : jsonp_ulong( gui->http, "pack_already_executed", cur->out.pack_already_executed - prev->out.pack_already_executed );
692 0 : jsonp_ulong( gui->http, "pack_retained", cur->out.pack_retained );
693 0 : jsonp_ulong( gui->http, "pack_wait_full", cur->out.pack_wait_full - prev->out.pack_wait_full );
694 0 : jsonp_ulong( gui->http, "pack_leader_slow", cur->out.pack_leader_slow - prev->out.pack_leader_slow );
695 0 : jsonp_ulong( gui->http, "bank_invalid", cur->out.bank_invalid - prev->out.bank_invalid );
696 0 : jsonp_ulong( gui->http, "bank_nonce_already_advanced", cur->out.bank_nonce_already_advanced - prev->out.bank_nonce_already_advanced );
697 0 : jsonp_ulong( gui->http, "bank_nonce_advance_failed", cur->out.bank_nonce_advance_failed - prev->out.bank_nonce_advance_failed );
698 0 : jsonp_ulong( gui->http, "bank_nonce_wrong_blockhash", cur->out.bank_nonce_wrong_blockhash - prev->out.bank_nonce_wrong_blockhash );
699 0 : jsonp_ulong( gui->http, "block_success", cur->out.block_success - prev->out.block_success );
700 0 : jsonp_ulong( gui->http, "block_fail", cur->out.block_fail - prev->out.block_fail );
701 0 : jsonp_close_object( gui->http );
702 0 : jsonp_close_object( gui->http );
703 0 : }
704 :
705 : void
706 : fd_gui_printf_live_txn_waterfall( fd_gui_t * gui,
707 : fd_gui_txn_waterfall_t const * prev,
708 : fd_gui_txn_waterfall_t const * cur,
709 0 : ulong next_leader_slot ) {
710 0 : jsonp_open_envelope( gui->http, "summary", "live_txn_waterfall" );
711 0 : jsonp_open_object( gui->http, "value" );
712 0 : jsonp_ulong( gui->http, "next_leader_slot", next_leader_slot );
713 0 : fd_gui_printf_waterfall( gui, prev, cur );
714 0 : jsonp_close_object( gui->http );
715 0 : jsonp_close_envelope( gui->http );
716 0 : }
717 :
718 : static void
719 : fd_gui_printf_network_metrics( fd_gui_t * gui,
720 0 : fd_gui_network_stats_t const * cur ) {
721 0 : jsonp_open_array( gui->http, "ingress" );
722 0 : jsonp_ulong( gui->http, NULL, cur->in.turbine );
723 0 : jsonp_ulong( gui->http, NULL, cur->in.gossip );
724 0 : jsonp_ulong( gui->http, NULL, cur->in.tpu );
725 0 : jsonp_ulong( gui->http, NULL, cur->in.repair );
726 0 : jsonp_ulong( gui->http, NULL, cur->in.rserve );
727 0 : jsonp_ulong( gui->http, NULL, cur->in.metric );
728 0 : jsonp_close_array( gui->http );
729 0 : jsonp_open_array( gui->http, "egress" );
730 0 : jsonp_ulong( gui->http, NULL, cur->out.turbine );
731 0 : jsonp_ulong( gui->http, NULL, cur->out.gossip );
732 0 : jsonp_ulong( gui->http, NULL, cur->out.tpu );
733 0 : jsonp_ulong( gui->http, NULL, cur->out.repair );
734 0 : jsonp_ulong( gui->http, NULL, cur->out.rserve );
735 0 : jsonp_ulong( gui->http, NULL, cur->out.metric );
736 0 : jsonp_close_array( gui->http );
737 0 : jsonp_open_array( gui->http, "ingress_ema" );
738 0 : for( ulong i=0UL; i<FD_GUI_NET_PROTO_CNT; i++ ) jsonp_double( gui->http, NULL, fd_double_if( gui->summary.net_rate_ema_ready, gui->summary.ingress_ema[ i ], 0.0 ) );
739 0 : jsonp_close_array( gui->http );
740 0 : jsonp_open_array( gui->http, "egress_ema" );
741 0 : for( ulong i=0UL; i<FD_GUI_NET_PROTO_CNT; i++ ) jsonp_double( gui->http, NULL, fd_double_if( gui->summary.net_rate_ema_ready, gui->summary.egress_ema[ i ], 0.0 ) );
742 0 : jsonp_close_array( gui->http );
743 0 : fd_gui_rate_entry_t const * ingress_max_head = fd_gui_rate_deque_empty( gui->summary.ingress_maxq ) ? NULL : fd_gui_rate_deque_peek_head_const( gui->summary.ingress_maxq );
744 0 : fd_gui_rate_entry_t const * egress_max_head = fd_gui_rate_deque_empty( gui->summary.egress_maxq ) ? NULL : fd_gui_rate_deque_peek_head_const( gui->summary.egress_maxq );
745 0 : jsonp_ulong( gui->http, "ingress_max_5m", ingress_max_head ? (ulong)ingress_max_head->value : 0UL );
746 0 : jsonp_ulong( gui->http, "egress_max_5m", egress_max_head ? (ulong)egress_max_head->value : 0UL );
747 0 : }
748 :
749 : void
750 : fd_gui_printf_live_network_metrics( fd_gui_t * gui,
751 0 : fd_gui_network_stats_t const * cur ) {
752 0 : jsonp_open_envelope( gui->http, "summary", "live_network_metrics" );
753 0 : jsonp_open_object( gui->http, "value" );
754 0 : fd_gui_printf_network_metrics( gui, cur );
755 0 : jsonp_close_object( gui->http );
756 0 : jsonp_close_envelope( gui->http );
757 0 : }
758 :
759 : static void
760 : fd_gui_printf_tile_stats( fd_gui_t * gui,
761 : fd_gui_tile_stats_t const * prev,
762 0 : fd_gui_tile_stats_t const * cur ) {
763 0 : jsonp_open_object( gui->http, "tile_primary_metric" );
764 0 : jsonp_ulong( gui->http, "quic", cur->quic_conn_cnt );
765 0 : jsonp_double( gui->http, "bundle_rtt_smoothed_millis", (double)(cur->bundle_rtt_smoothed_nanos) / 1000000.0 );
766 :
767 0 : fd_histf_t bundle_rx_delay_hist_delta[ 1 ];
768 0 : fd_histf_subtract( &cur->bundle_rx_delay_hist, &prev->bundle_rx_delay_hist, bundle_rx_delay_hist_delta );
769 0 : ulong bundle_rx_delay_nanos_p90 = fd_histf_percentile( bundle_rx_delay_hist_delta, 90U, ULONG_MAX );
770 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 ));
771 :
772 0 : if( FD_LIKELY( cur->sample_time_nanos>prev->sample_time_nanos ) ) {
773 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) ));
774 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) ));
775 0 : } else {
776 0 : jsonp_ulong( gui->http, "net_in", 0 );
777 0 : jsonp_ulong( gui->http, "net_out", 0 );
778 0 : }
779 0 : if( FD_LIKELY( cur->verify_total_cnt>prev->verify_total_cnt ) ) {
780 0 : jsonp_double( gui->http, "verify", (double)(cur->verify_drop_cnt-prev->verify_drop_cnt) / (double)(cur->verify_total_cnt-prev->verify_total_cnt) );
781 0 : } else {
782 0 : jsonp_double( gui->http, "verify", 0.0 );
783 0 : }
784 0 : if( FD_LIKELY( cur->dedup_total_cnt>prev->dedup_total_cnt ) ) {
785 0 : jsonp_double( gui->http, "dedup", (double)(cur->dedup_drop_cnt-prev->dedup_drop_cnt) / (double)(cur->dedup_total_cnt-prev->dedup_total_cnt) );
786 0 : } else {
787 0 : jsonp_double( gui->http, "dedup", 0.0 );
788 0 : }
789 0 : jsonp_ulong( gui->http, "bank", cur->bank_txn_exec_cnt - prev->bank_txn_exec_cnt );
790 0 : jsonp_double( gui->http, "pack", !cur->pack_buffer_capacity ? 1.0 : (double)cur->pack_buffer_cnt/(double)cur->pack_buffer_capacity );
791 0 : jsonp_double( gui->http, "poh", 0.0 );
792 0 : jsonp_double( gui->http, "shred", 0.0 );
793 0 : jsonp_double( gui->http, "store", 0.0 );
794 0 : jsonp_close_object( gui->http );
795 0 : }
796 :
797 : void
798 : fd_gui_printf_live_tile_stats( fd_gui_t * gui,
799 : fd_gui_tile_stats_t const * prev,
800 0 : fd_gui_tile_stats_t const * cur ) {
801 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_primary_metric" );
802 0 : jsonp_open_object( gui->http, "value" );
803 0 : jsonp_ulong( gui->http, "next_leader_slot", 0UL );
804 0 : fd_gui_printf_tile_stats( gui, prev, cur );
805 0 : jsonp_close_object( gui->http );
806 0 : jsonp_close_envelope( gui->http );
807 0 : }
808 :
809 : static void
810 : fd_gui_printf_tile_timers( fd_gui_t * gui,
811 : fd_gui_tile_timers_t const * prev,
812 0 : fd_gui_tile_timers_t const * cur ) {
813 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
814 0 : ulong t = gui->summary.tile[ i ];
815 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ t ];
816 :
817 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
818 : /* bench tiles not reported */
819 0 : continue;
820 0 : }
821 :
822 0 : ulong cur_total = 0UL;
823 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++ ) cur_total += cur[ t ].timers[ j ];
824 :
825 0 : ulong prev_total = 0UL;
826 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++ ) prev_total += prev[ t ].timers[ j ];
827 :
828 0 : double idle_ratio;
829 0 : if( FD_UNLIKELY( cur_total==prev_total ) ) {
830 : /* The tile didn't sample timers since the last sample, unclear what
831 : idleness should be so send -1. NaN would be better but no NaN in
832 : JSON. */
833 0 : idle_ratio = -1;
834 0 : } else {
835 0 : ulong idle_time = cur[ t ].timers[ FD_METRICS_ENUM_TILE_REGIME_V_CAUGHT_UP_POSTFRAG_IDX ] - prev[ t ].timers[ FD_METRICS_ENUM_TILE_REGIME_V_CAUGHT_UP_POSTFRAG_IDX ];
836 0 : ulong backpressure_time = cur[ t ].timers[ FD_METRICS_ENUM_TILE_REGIME_V_BACKPRESSURE_PREFRAG_IDX ] - prev[ t ].timers[ FD_METRICS_ENUM_TILE_REGIME_V_BACKPRESSURE_PREFRAG_IDX ];
837 0 : idle_ratio = (double)(idle_time+backpressure_time) / (double)(cur_total - prev_total);
838 0 : }
839 :
840 0 : jsonp_double( gui->http, NULL, idle_ratio );
841 0 : }
842 0 : }
843 :
844 : static void
845 : fd_gui_printf_tile_metrics( fd_gui_t * gui,
846 : fd_gui_tile_timers_t const * prev,
847 0 : fd_gui_tile_timers_t const * cur ) {
848 0 : jsonp_open_array( gui->http, "timers" );
849 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
850 0 : ulong t = gui->summary.tile[ i ];
851 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ t ];
852 :
853 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
854 : /* bench tiles not reported */
855 0 : jsonp_null( gui->http, NULL );
856 0 : continue;
857 0 : }
858 :
859 0 : ulong cur_total = 0UL;
860 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++ ) cur_total += cur[ t ].timers[ j ];
861 :
862 0 : ulong prev_total = 0UL;
863 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++ ) prev_total += prev[ t ].timers[ j ];
864 :
865 0 : if( FD_UNLIKELY( cur_total==prev_total ) ) {
866 0 : jsonp_null( gui->http, NULL );
867 0 : } else {
868 0 : jsonp_open_array( gui->http, NULL );
869 0 : for (ulong j = 0UL; j<FD_METRICS_ENUM_TILE_REGIME_CNT; j++) {
870 0 : double percent = ((double)(cur[ t ].timers[ j ] - prev[ t ].timers[ j ]) / (double)(cur_total-prev_total)) * 100.0;
871 0 : double percent_trunc = (double)((long)(percent * 100.0)) / 100.0;
872 0 : jsonp_double( gui->http, NULL, percent_trunc );
873 0 : }
874 0 : jsonp_close_array( gui->http );
875 0 : }
876 0 : }
877 0 : jsonp_close_array( gui->http );
878 :
879 0 : jsonp_open_array( gui->http, "sched_timers" );
880 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
881 0 : ulong t = gui->summary.tile[ i ];
882 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ t ];
883 :
884 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
885 : /* bench tiles not reported */
886 0 : jsonp_null( gui->http, NULL );
887 0 : continue;
888 0 : }
889 :
890 0 : ulong cur_total = 0UL;
891 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_CPU_REGIME_CNT; j++ ) cur_total += cur[ t ].sched_timers[ j ];
892 :
893 0 : ulong prev_total = 0UL;
894 0 : for( ulong j=0UL; j<FD_METRICS_ENUM_CPU_REGIME_CNT; j++ ) prev_total += prev[ t ].sched_timers[ j ];
895 :
896 0 : if( FD_UNLIKELY( cur_total==prev_total ) ) {
897 0 : jsonp_null( gui->http, NULL );
898 0 : } else {
899 0 : jsonp_open_array( gui->http, NULL );
900 0 : for (ulong j = 0UL; j<FD_METRICS_ENUM_CPU_REGIME_CNT; j++) {
901 0 : double percent = ((double)(cur[ t ].sched_timers[ j ] - prev[ t ].sched_timers[ j ]) / (double)(cur_total-prev_total)) * 100.0;
902 0 : double percent_trunc = (double)((long)(percent * 100.0)) / 100.0;
903 0 : jsonp_double( gui->http, NULL, percent_trunc );
904 0 : }
905 0 : jsonp_close_array( gui->http );
906 0 : }
907 0 : }
908 0 : jsonp_close_array( gui->http );
909 :
910 0 : jsonp_open_array( gui->http, "in_backp" );
911 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
912 0 : jsonp_bool( gui->http, NULL, cur[ gui->summary.tile[ i ] ].in_backp );
913 0 : }
914 0 : jsonp_close_array( gui->http );
915 0 : jsonp_open_array( gui->http, "backp_msgs" );
916 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
917 0 : jsonp_ulong( gui->http, NULL, cur[ gui->summary.tile[ i ] ].backp_cnt );
918 0 : }
919 0 : jsonp_close_array( gui->http );
920 0 : jsonp_open_array( gui->http, "alive" );
921 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
922 0 : ulong t = gui->summary.tile[ i ];
923 : /* We use a longer sampling window for this metric to minimize
924 : false positives */
925 0 : jsonp_ulong( gui->http, NULL, fd_ulong_if( cur[ t ].status==2U, 2UL, (ulong)(cur[ t ].heartbeat>prev[ t ].heartbeat) ) );
926 0 : }
927 0 : jsonp_close_array( gui->http );
928 0 : jsonp_open_array( gui->http, "nvcsw" );
929 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
930 0 : jsonp_ulong( gui->http, NULL, cur[ gui->summary.tile[ i ] ].nvcsw );
931 0 : }
932 0 : jsonp_close_array( gui->http );
933 0 : jsonp_open_array( gui->http, "nivcsw" );
934 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
935 0 : jsonp_ulong( gui->http, NULL, cur[ gui->summary.tile[ i ] ].nivcsw );
936 0 : }
937 0 : jsonp_close_array( gui->http );
938 0 : jsonp_open_array( gui->http, "minflt" );
939 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
940 0 : jsonp_ulong( gui->http, NULL, cur[ gui->summary.tile[ i ] ].minflt );
941 0 : }
942 0 : jsonp_close_array( gui->http );
943 0 : jsonp_open_array( gui->http, "majflt" );
944 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
945 0 : jsonp_ulong( gui->http, NULL, cur[ gui->summary.tile[ i ] ].majflt );
946 0 : }
947 0 : jsonp_close_array( gui->http );
948 0 : jsonp_open_array( gui->http, "last_cpu" );
949 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
950 0 : jsonp_ulong( gui->http, NULL, cur[ gui->summary.tile[ i ] ].last_cpu );
951 0 : }
952 0 : jsonp_close_array( gui->http );
953 0 : jsonp_open_array( gui->http, "interrupts" );
954 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
955 0 : jsonp_ulong( gui->http, NULL, cur[ gui->summary.tile[ i ] ].interrupts );
956 0 : }
957 0 : jsonp_close_array( gui->http );
958 0 : jsonp_open_array( gui->http, "priority" );
959 0 : for( ulong i=0UL; i<gui->summary.tile_cnt; i++ ) {
960 0 : int priority = fd_topob_tile_priority_type( gui->topo->tiles[ gui->summary.tile[ i ] ].name );
961 :
962 0 : char const * priority_type_str = "unknown";
963 0 : switch( priority ) {
964 0 : case FD_TOPOB_PRIORITY_FLOATING: priority_type_str = "floating"; break;
965 0 : case FD_TOPOB_PRIORITY_STARTUP: priority_type_str = "startup"; break;
966 0 : case FD_TOPOB_PRIORITY_NORMAL: priority_type_str = "normal"; break;
967 0 : case FD_TOPOB_PRIORITY_CRITICAL: priority_type_str = "critical"; break;
968 0 : }
969 :
970 0 : jsonp_string( gui->http, NULL, priority_type_str );
971 0 : }
972 0 : jsonp_close_array( gui->http );
973 0 : }
974 :
975 : void
976 0 : fd_gui_printf_live_tile_timers( fd_gui_t * gui ) {
977 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_timers" );
978 0 : jsonp_open_array( gui->http, "value" );
979 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) * gui->tile_cnt;
980 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) * gui->tile_cnt;
981 0 : fd_gui_printf_tile_timers( gui, prev, cur );
982 0 : jsonp_close_array( gui->http );
983 0 : jsonp_close_envelope( gui->http );
984 0 : }
985 :
986 : void
987 0 : fd_gui_printf_live_tile_metrics( fd_gui_t * gui ) {
988 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) * gui->tile_cnt;
989 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) * gui->tile_cnt;
990 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_metrics" );
991 0 : jsonp_open_object( gui->http, "value" );
992 0 : fd_gui_printf_tile_metrics( gui, prev, cur );
993 0 : jsonp_close_object( gui->http );
994 0 : jsonp_close_envelope( gui->http );
995 0 : }
996 :
997 : void
998 0 : fd_gui_printf_estimated_tps( fd_gui_t * gui ) {
999 0 : ulong idx = (gui->summary.estimated_tps_history_idx+FD_GUI_TPS_HISTORY_SAMPLE_CNT-1UL) % FD_GUI_TPS_HISTORY_SAMPLE_CNT;
1000 :
1001 0 : jsonp_open_envelope( gui->http, "summary", "estimated_tps" );
1002 0 : jsonp_open_object( gui->http, "value" );
1003 0 : ulong vote_cnt = gui->summary.estimated_tps_history[ idx ].vote_failed
1004 0 : + gui->summary.estimated_tps_history[ idx ].vote_success;
1005 0 : ulong total_cnt = vote_cnt
1006 0 : + gui->summary.estimated_tps_history[ idx ].nonvote_success
1007 0 : + gui->summary.estimated_tps_history[ idx ].nonvote_failed;
1008 0 : jsonp_double( gui->http, "total", (double)total_cnt/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
1009 0 : jsonp_double( gui->http, "vote", (double)vote_cnt/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
1010 0 : jsonp_double( gui->http, "nonvote_success", (double)gui->summary.estimated_tps_history[ idx ].nonvote_success/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
1011 0 : jsonp_double( gui->http, "nonvote_failed", (double)gui->summary.estimated_tps_history[ idx ].nonvote_failed/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
1012 0 : jsonp_close_object( gui->http );
1013 0 : jsonp_close_envelope( gui->http );
1014 0 : }
1015 :
1016 : void
1017 0 : fd_gui_printf_live_program_cache( fd_gui_t * gui ) {
1018 0 : fd_topo_t const * topo = gui->topo;
1019 :
1020 0 : ulong insertions = 0UL;
1021 0 : ulong insertion_bytes = 0UL;
1022 0 : ulong evictions = 0UL;
1023 0 : ulong eviction_bytes = 0UL;
1024 0 : ulong spills = 0UL;
1025 0 : ulong spill_bytes = 0UL;
1026 :
1027 0 : for( ulong i=0UL; i<gui->summary.execrp_tile_cnt; i++ ) {
1028 0 : fd_topo_tile_t const * execrp = &topo->tiles[ fd_topo_find_tile( topo, "execrp", i ) ];
1029 0 : volatile ulong const * metrics = fd_metrics_tile( execrp->metrics );
1030 :
1031 0 : insertions += metrics[ MIDX( COUNTER, EXECRP, PROGCACHE_FILL ) ];
1032 0 : insertion_bytes += metrics[ MIDX( COUNTER, EXECRP, PROGCACHE_FILL_BYTES ) ];
1033 0 : evictions += metrics[ MIDX( COUNTER, EXECRP, PROGCACHE_EVICTION ) ];
1034 0 : eviction_bytes += metrics[ MIDX( COUNTER, EXECRP, PROGCACHE_EVICTION_BYTES ) ];
1035 0 : spills += metrics[ MIDX( COUNTER, EXECRP, PROGCACHE_SPILL ) ];
1036 0 : spill_bytes += metrics[ MIDX( COUNTER, EXECRP, PROGCACHE_SPILL_BYTES ) ];
1037 0 : }
1038 :
1039 0 : ulong free_bytes = 0UL;
1040 0 : ulong size_bytes = 0UL;
1041 :
1042 0 : fd_topo_tile_t const * replay = &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ];
1043 0 : volatile ulong const * replay_metrics = fd_metrics_tile( replay->metrics );
1044 :
1045 0 : free_bytes = replay_metrics[ MIDX( GAUGE, REPLAY, PROGCACHE_FREE_BYTES ) ];
1046 0 : size_bytes = replay_metrics[ MIDX( GAUGE, REPLAY, PROGCACHE_SIZE_BYTES ) ];
1047 :
1048 0 : jsonp_open_envelope( gui->http, "summary", "live_program_cache" );
1049 0 : jsonp_open_object( gui->http, "value" );
1050 0 : jsonp_ulong( gui->http, "hits", gui->summary.progcache_hits_1min );
1051 0 : jsonp_ulong( gui->http, "lookups", gui->summary.progcache_lookups_1min );
1052 0 : jsonp_ulong( gui->http, "insertions", insertions );
1053 0 : jsonp_ulong( gui->http, "insertion_bytes", insertion_bytes );
1054 0 : jsonp_ulong( gui->http, "evictions", evictions );
1055 0 : jsonp_ulong( gui->http, "eviction_bytes", eviction_bytes );
1056 0 : jsonp_ulong( gui->http, "spills", spills );
1057 0 : jsonp_ulong( gui->http, "spill_bytes", spill_bytes );
1058 0 : jsonp_ulong( gui->http, "free_bytes", free_bytes );
1059 0 : jsonp_ulong( gui->http, "size_bytes", size_bytes );
1060 0 : jsonp_close_object( gui->http );
1061 0 : jsonp_close_envelope( gui->http );
1062 0 : }
1063 :
1064 : void
1065 0 : fd_gui_printf_health( fd_gui_t * gui ) {
1066 0 : fd_topo_t const * topo = gui->topo;
1067 :
1068 0 : ulong diag_tile_idx = fd_topo_find_tile( topo, "diag", 0UL );
1069 :
1070 : /* Default to disabled if no diag tile */
1071 0 : ulong bundle_status = FD_DIAG_BUNDLE_STATUS_DISABLED;
1072 0 : ulong vote_status = FD_DIAG_VOTE_STATUS_DISABLED;
1073 0 : ulong replay_status = FD_DIAG_REPLAY_STATUS_DISABLED;
1074 0 : ulong turbine_status = FD_DIAG_TURBINE_STATUS_DISABLED;
1075 :
1076 0 : if( FD_LIKELY( diag_tile_idx!=ULONG_MAX ) ) {
1077 0 : volatile ulong const * metrics = fd_metrics_tile( topo->tiles[ diag_tile_idx ].metrics );
1078 0 : bundle_status = metrics[ MIDX( GAUGE, DIAG, BUNDLE_STATUS ) ];
1079 0 : vote_status = metrics[ MIDX( GAUGE, DIAG, VOTE_STATUS ) ];
1080 0 : replay_status = metrics[ MIDX( GAUGE, DIAG, REPLAY_STATUS ) ];
1081 0 : turbine_status = metrics[ MIDX( GAUGE, DIAG, TURBINE_STATUS ) ];
1082 0 : }
1083 :
1084 0 : if( FD_UNLIKELY( !gui->summary.is_full_client ) ) {
1085 0 : switch( gui->summary.vote_state ) {
1086 0 : case FD_GUI_VOTE_STATE_VOTING: vote_status = FD_DIAG_VOTE_STATUS_VOTING; break;
1087 0 : case FD_GUI_VOTE_STATE_DELINQUENT: vote_status = FD_DIAG_VOTE_STATUS_DELINQUENT; break;
1088 0 : default: vote_status = FD_DIAG_VOTE_STATUS_DISABLED; break;
1089 0 : }
1090 0 : replay_status = FD_DIAG_REPLAY_STATUS_DISABLED;
1091 0 : turbine_status = FD_DIAG_TURBINE_STATUS_DISABLED;
1092 0 : }
1093 :
1094 : /* Map bundle status to string */
1095 0 : char const * bundle_str;
1096 0 : switch( bundle_status ) {
1097 0 : case FD_DIAG_BUNDLE_STATUS_DISCONNECTED: bundle_str = "disconnected"; break;
1098 0 : case FD_DIAG_BUNDLE_STATUS_CONNECTING: bundle_str = "connecting"; break;
1099 0 : case FD_DIAG_BUNDLE_STATUS_CONNECTED: bundle_str = "connected"; break;
1100 0 : case FD_DIAG_BUNDLE_STATUS_SLEEPING: bundle_str = "sleeping"; break;
1101 0 : default: bundle_str = "disabled"; break;
1102 0 : }
1103 :
1104 : /* Map vote status to string */
1105 0 : char const * vote_str;
1106 0 : switch( vote_status ) {
1107 0 : case FD_DIAG_VOTE_STATUS_NOT_STARTED: vote_str = "not_started"; break;
1108 0 : case FD_DIAG_VOTE_STATUS_DELINQUENT: vote_str = "delinquent"; break;
1109 0 : case FD_DIAG_VOTE_STATUS_VOTING: vote_str = "voting"; break;
1110 0 : default: vote_str = "disabled"; break;
1111 0 : }
1112 :
1113 : /* Map replay status to string */
1114 0 : char const * replay_str;
1115 0 : switch( replay_status ) {
1116 0 : case FD_DIAG_REPLAY_STATUS_NOT_STARTED: replay_str = "not_started"; break;
1117 0 : case FD_DIAG_REPLAY_STATUS_BEHIND: replay_str = "behind"; break;
1118 0 : case FD_DIAG_REPLAY_STATUS_RUNNING: replay_str = "running"; break;
1119 0 : default: replay_str = "disabled"; break;
1120 0 : }
1121 :
1122 : /* Map turbine status to string */
1123 0 : char const * turbine_str;
1124 0 : switch( turbine_status ) {
1125 0 : case FD_DIAG_TURBINE_STATUS_NOT_STARTED: turbine_str = "not_started"; break;
1126 0 : case FD_DIAG_TURBINE_STATUS_STALLED: turbine_str = "stalled"; break;
1127 0 : case FD_DIAG_TURBINE_STATUS_REPAIR_OUTPACING: turbine_str = "repair_outpacing"; break;
1128 0 : case FD_DIAG_TURBINE_STATUS_RUNNING: turbine_str = "running"; break;
1129 0 : default: turbine_str = "disabled"; break;
1130 0 : }
1131 :
1132 0 : jsonp_open_envelope( gui->http, "summary", "health" );
1133 0 : jsonp_open_object( gui->http, "value" );
1134 0 : jsonp_string( gui->http, "vote", vote_str );
1135 0 : jsonp_string( gui->http, "bundle", bundle_str );
1136 0 : jsonp_string( gui->http, "replay", replay_str );
1137 0 : jsonp_string( gui->http, "turbine", turbine_str );
1138 0 : jsonp_close_object( gui->http );
1139 0 : jsonp_close_envelope( gui->http );
1140 0 : }
1141 :
1142 : /* Triangular-weighted average of a delta ring. Newest sample has
1143 : weight n, oldest has weight 1. Returns sum(w*delta) / weighted_dt
1144 : where weighted_dt is precomputed (sum of w * dt_sec for the same
1145 : samples). */
1146 : static double
1147 : fd_gui_accdb_weighted_rate( ulong const * ring,
1148 : ulong next_write_idx,
1149 : ulong n,
1150 0 : double weighted_dt ) {
1151 0 : if( !n || weighted_dt<=0.0 ) return 0.0;
1152 0 : double num = 0.0;
1153 0 : for( ulong k=0UL; k<n; k++ ) {
1154 0 : double w = (double)(n - k);
1155 0 : ulong ri = (next_write_idx + FD_GUI_ACCDB_WIN_SAMPLES - 1UL - k) % FD_GUI_ACCDB_WIN_SAMPLES;
1156 0 : num += w * (double)ring[ ri ];
1157 0 : }
1158 0 : return num / weighted_dt;
1159 0 : }
1160 :
1161 : void
1162 0 : fd_gui_printf_accounts_stats( fd_gui_t * gui ) {
1163 0 : fd_gui_accounts_stats_t const * cur = gui->summary.accounts_stats_current;
1164 0 : fd_gui_accounts_stats_t const * prev = gui->summary.accounts_stats_reference;
1165 0 : int have_ref = gui->summary.accounts_stats_have_reference;
1166 :
1167 0 : long dt_nanos = have_ref ? (cur->sample_time_nanos - prev->sample_time_nanos) : 0L;
1168 :
1169 : /* Append this snap's deltas to the triangular-window rings. The
1170 : emit code below applies triangular weights to compute the smoothed
1171 : rate. Buffer is a simple ring; idx points to the next write slot. */
1172 0 : if( have_ref && dt_nanos>0L ) {
1173 0 : ulong i = gui->summary.accdb_win_idx;
1174 :
1175 0 : gui->summary.accdb_win_dt_nanos [ i ] = dt_nanos;
1176 0 : gui->summary.agg_acquired_win [ i ] = cur->acquired - prev->acquired ;
1177 0 : gui->summary.agg_acquired_writable_win [ i ] = cur->acquired_writable - prev->acquired_writable ;
1178 0 : gui->summary.agg_bytes_read_win [ i ] = cur->bytes_read - prev->bytes_read ;
1179 0 : gui->summary.agg_bytes_copied_win [ i ] = cur->bytes_copied - prev->bytes_copied ;
1180 0 : gui->summary.agg_bytes_written_win [ i ] = cur->bytes_written - prev->bytes_written ;
1181 0 : gui->summary.agg_bytes_written_accdb_win [ i ] = cur->bytes_written_accdb - prev->bytes_written_accdb ;
1182 0 : gui->summary.agg_read_ops_win [ i ] = cur->read_ops - prev->read_ops ;
1183 0 : gui->summary.agg_write_ops_win [ i ] = cur->write_ops - prev->write_ops ;
1184 0 : gui->summary.agg_relocated_bytes_win [ i ] = cur->accounts_relocated_bytes - prev->accounts_relocated_bytes;
1185 :
1186 0 : ulong agg_misses_delta = 0UL;
1187 0 : for( ulong c=0UL; c<FD_ACCDB_CACHE_CLASS_CNT; c++ ) {
1188 0 : ulong d = cur->not_found_per_class[ c ] - prev->not_found_per_class[ c ];
1189 0 : agg_misses_delta += d;
1190 0 : gui->summary.class_acq_win [ c ][ i ] = cur->acquired_per_class [ c ] - prev->acquired_per_class [ c ];
1191 0 : gui->summary.class_acq_wr_win [ c ][ i ] = cur->acquired_writable_per_class [ c ] - prev->acquired_writable_per_class [ c ];
1192 0 : gui->summary.class_not_found_win [ c ][ i ] = d;
1193 0 : gui->summary.class_evicted_win [ c ][ i ] = cur->evicted_per_class [ c ] - prev->evicted_per_class [ c ];
1194 0 : gui->summary.class_preevicted_win [ c ][ i ] = cur->preevicted_per_class [ c ] - prev->preevicted_per_class [ c ];
1195 0 : gui->summary.class_commit_new_win [ c ][ i ] = cur->committed_new_per_class [ c ] - prev->committed_new_per_class [ c ];
1196 0 : gui->summary.class_commit_over_win[ c ][ i ] = cur->committed_overwrite_per_class [ c ] - prev->committed_overwrite_per_class [ c ];
1197 0 : }
1198 0 : gui->summary.agg_misses_win[ i ] = agg_misses_delta;
1199 :
1200 : /* Per-partition deltas. Snap each partition's current cumulative
1201 : counters from accdb_shmem, diff against prev, push into ring.
1202 : Also keep the most-recent snapshot for non-rate fields. */
1203 0 : if( FD_LIKELY( gui->accdb_shmem ) ) {
1204 0 : ulong pcnt = fd_accdb_shmem_partition_max( gui->accdb_shmem );
1205 0 : if( pcnt>FD_GUI_MAX_PARTITIONS ) pcnt = FD_GUI_MAX_PARTITIONS;
1206 0 : gui->summary.partition_cnt = pcnt;
1207 0 : for( ulong p=0UL; p<pcnt; p++ ) {
1208 0 : fd_accdb_shmem_partition_info_t info;
1209 0 : fd_accdb_shmem_partition_info( gui->accdb_shmem, p, &info );
1210 0 : gui->summary.partitions[ p ] = info;
1211 :
1212 : /* Pool slots get reused: when a partition is released and
1213 : re-acquired, change_partition zeroes its counters. Detect
1214 : the reset (any counter dropped below its previous value) and
1215 : treat this sample as the start of a new lifecycle — emit a
1216 : zero delta rather than letting the unsigned subtract wrap
1217 : into a giant rate. */
1218 0 : int reset = info.read_ops < gui->summary.partition_prev_read_ops [ p ] ||
1219 0 : info.bytes_read < gui->summary.partition_prev_bytes_read [ p ] ||
1220 0 : info.write_ops < gui->summary.partition_prev_write_ops [ p ] ||
1221 0 : info.bytes_written < gui->summary.partition_prev_bytes_written[ p ];
1222 0 : if( FD_UNLIKELY( reset ) ) {
1223 0 : gui->summary.partition_prev_read_ops [ p ] = info.read_ops;
1224 0 : gui->summary.partition_prev_bytes_read [ p ] = info.bytes_read;
1225 0 : gui->summary.partition_prev_write_ops [ p ] = info.write_ops;
1226 0 : gui->summary.partition_prev_bytes_written[ p ] = info.bytes_written;
1227 : /* Also wipe the historical window so an old lifecycle's
1228 : samples don't keep contributing to this slot's rate. */
1229 0 : for( ulong k=0UL; k<FD_GUI_ACCDB_WIN_SAMPLES; k++ ) {
1230 0 : gui->summary.partition_read_ops_win [ p ][ k ] = 0UL;
1231 0 : gui->summary.partition_bytes_read_win [ p ][ k ] = 0UL;
1232 0 : gui->summary.partition_write_ops_win [ p ][ k ] = 0UL;
1233 0 : gui->summary.partition_bytes_written_win[p ][ k ] = 0UL;
1234 0 : }
1235 0 : }
1236 0 : ulong d_read_ops = info.read_ops - gui->summary.partition_prev_read_ops [ p ];
1237 0 : ulong d_bytes_read = info.bytes_read - gui->summary.partition_prev_bytes_read [ p ];
1238 0 : ulong d_write_ops = info.write_ops - gui->summary.partition_prev_write_ops [ p ];
1239 0 : ulong d_bytes_written = info.bytes_written - gui->summary.partition_prev_bytes_written[ p ];
1240 :
1241 0 : gui->summary.partition_read_ops_win [ p ][ i ] = d_read_ops;
1242 0 : gui->summary.partition_bytes_read_win [ p ][ i ] = d_bytes_read;
1243 0 : gui->summary.partition_write_ops_win [ p ][ i ] = d_write_ops;
1244 0 : gui->summary.partition_bytes_written_win[p ][ i ] = d_bytes_written;
1245 :
1246 0 : gui->summary.partition_prev_read_ops [ p ] = info.read_ops;
1247 0 : gui->summary.partition_prev_bytes_read [ p ] = info.bytes_read;
1248 0 : gui->summary.partition_prev_write_ops [ p ] = info.write_ops;
1249 0 : gui->summary.partition_prev_bytes_written[ p ] = info.bytes_written;
1250 0 : }
1251 0 : }
1252 :
1253 : /* Per-tile deltas. Cumulative values were snapped from each tile's
1254 : metric page in fd_gui_accounts_stats_snap; diff against prev and
1255 : push into the ring. */
1256 0 : for( ulong s=0UL; s<gui->summary.accdb_tile_cnt; s++ ) {
1257 0 : gui->summary.tile_acquired_win [ s ][ i ] = gui->summary.tile_cur_acquired [ s ] - gui->summary.tile_prev_acquired [ s ];
1258 0 : gui->summary.tile_acquired_writable_win[ s ][ i ] = gui->summary.tile_cur_acquired_writable[ s ] - gui->summary.tile_prev_acquired_writable[ s ];
1259 0 : gui->summary.tile_bytes_read_win [ s ][ i ] = gui->summary.tile_cur_bytes_read [ s ] - gui->summary.tile_prev_bytes_read [ s ];
1260 0 : gui->summary.tile_bytes_copied_win [ s ][ i ] = gui->summary.tile_cur_bytes_copied [ s ] - gui->summary.tile_prev_bytes_copied [ s ];
1261 0 : gui->summary.tile_bytes_written_win [ s ][ i ] = gui->summary.tile_cur_bytes_written [ s ] - gui->summary.tile_prev_bytes_written [ s ];
1262 0 : gui->summary.tile_read_ops_win [ s ][ i ] = gui->summary.tile_cur_read_ops [ s ] - gui->summary.tile_prev_read_ops [ s ];
1263 0 : gui->summary.tile_write_ops_win [ s ][ i ] = gui->summary.tile_cur_write_ops [ s ] - gui->summary.tile_prev_write_ops [ s ];
1264 0 : gui->summary.tile_misses_win [ s ][ i ] = gui->summary.tile_cur_misses [ s ] - gui->summary.tile_prev_misses [ s ];
1265 0 : gui->summary.tile_evicted_win [ s ][ i ] = gui->summary.tile_cur_evicted [ s ] - gui->summary.tile_prev_evicted [ s ];
1266 0 : gui->summary.tile_committed_win [ s ][ i ] = gui->summary.tile_cur_committed [ s ] - gui->summary.tile_prev_committed [ s ];
1267 0 : gui->summary.tile_acquire_calls_win [ s ][ i ] = gui->summary.tile_cur_acquire_calls [ s ] - gui->summary.tile_prev_acquire_calls [ s ];
1268 :
1269 0 : gui->summary.tile_prev_acquired [ s ] = gui->summary.tile_cur_acquired [ s ];
1270 0 : gui->summary.tile_prev_acquired_writable[ s ] = gui->summary.tile_cur_acquired_writable[ s ];
1271 0 : gui->summary.tile_prev_bytes_read [ s ] = gui->summary.tile_cur_bytes_read [ s ];
1272 0 : gui->summary.tile_prev_bytes_copied [ s ] = gui->summary.tile_cur_bytes_copied [ s ];
1273 0 : gui->summary.tile_prev_bytes_written [ s ] = gui->summary.tile_cur_bytes_written [ s ];
1274 0 : gui->summary.tile_prev_read_ops [ s ] = gui->summary.tile_cur_read_ops [ s ];
1275 0 : gui->summary.tile_prev_write_ops [ s ] = gui->summary.tile_cur_write_ops [ s ];
1276 0 : gui->summary.tile_prev_misses [ s ] = gui->summary.tile_cur_misses [ s ];
1277 0 : gui->summary.tile_prev_evicted [ s ] = gui->summary.tile_cur_evicted [ s ];
1278 0 : gui->summary.tile_prev_committed [ s ] = gui->summary.tile_cur_committed [ s ];
1279 0 : gui->summary.tile_prev_acquire_calls [ s ] = gui->summary.tile_cur_acquire_calls [ s ];
1280 :
1281 : /* 60s sparkline accumulator. Sum this snap's delta into the
1282 : in-flight 1-second bucket; when the bucket closes (>=1s since
1283 : it opened), shift the history rings right (newest at index 0)
1284 : and start a new bucket with the leftover delta. */
1285 0 : ulong d_acq = gui->summary.tile_acquired_win [ s ][ i ];
1286 0 : ulong d_acq_wr = gui->summary.tile_acquired_writable_win[ s ][ i ];
1287 0 : gui->summary.tile_sparkline_acq_bucket [ s ] += d_acq;
1288 0 : gui->summary.tile_sparkline_acq_wr_bucket[ s ] += d_acq_wr;
1289 :
1290 0 : long bucket_age = cur->sample_time_nanos - gui->summary.tile_sparkline_bucket_start_nanos[ s ];
1291 0 : if( gui->summary.tile_sparkline_bucket_start_nanos[ s ]==0L ) {
1292 : /* First snap for this slot — just open a bucket. */
1293 0 : gui->summary.tile_sparkline_bucket_start_nanos[ s ] = cur->sample_time_nanos;
1294 0 : } else if( bucket_age>=FD_GUI_ACCDB_SPARKLINE_BUCKET_NS ) {
1295 : /* Close the bucket: normalize to per-second, shift right, push. */
1296 0 : double secs = (double)bucket_age / 1e9;
1297 0 : double acq_rate = (double)gui->summary.tile_sparkline_acq_bucket [ s ] / secs;
1298 0 : double acq_wr_rate = (double)gui->summary.tile_sparkline_acq_wr_bucket[ s ] / secs;
1299 0 : memmove( &gui->summary.tile_sparkline_acq_history [ s ][ 1 ],
1300 0 : &gui->summary.tile_sparkline_acq_history [ s ][ 0 ],
1301 0 : (FD_GUI_ACCDB_SPARKLINE_SAMPLES-1UL)*sizeof(double) );
1302 0 : memmove( &gui->summary.tile_sparkline_acq_wr_history[ s ][ 1 ],
1303 0 : &gui->summary.tile_sparkline_acq_wr_history[ s ][ 0 ],
1304 0 : (FD_GUI_ACCDB_SPARKLINE_SAMPLES-1UL)*sizeof(double) );
1305 0 : gui->summary.tile_sparkline_acq_history [ s ][ 0 ] = acq_rate;
1306 0 : gui->summary.tile_sparkline_acq_wr_history[ s ][ 0 ] = acq_wr_rate;
1307 0 : if( gui->summary.tile_sparkline_count[ s ]<FD_GUI_ACCDB_SPARKLINE_SAMPLES )
1308 0 : gui->summary.tile_sparkline_count[ s ]++;
1309 0 : gui->summary.tile_sparkline_acq_bucket [ s ] = 0UL;
1310 0 : gui->summary.tile_sparkline_acq_wr_bucket [ s ] = 0UL;
1311 0 : gui->summary.tile_sparkline_bucket_start_nanos[ s ] = cur->sample_time_nanos;
1312 0 : }
1313 0 : }
1314 :
1315 0 : gui->summary.accdb_win_idx = (i+1UL) % FD_GUI_ACCDB_WIN_SAMPLES;
1316 0 : if( gui->summary.accdb_win_count<FD_GUI_ACCDB_WIN_SAMPLES )
1317 0 : gui->summary.accdb_win_count++;
1318 0 : }
1319 :
1320 : /* Compute weighted denominator once: sum(weight * dt_sec). Newest
1321 : sample has weight n, oldest has weight 1. If unfilled, only the
1322 : count samples are used (so first-snap rate is meaningful). */
1323 0 : ulong n = gui->summary.accdb_win_count;
1324 0 : double weighted_dt = 0.0;
1325 0 : for( ulong k=0UL; k<n; k++ ) {
1326 : /* k=0 is newest, k=n-1 is oldest; weight = n - k */
1327 0 : double w = (double)(n - k);
1328 : /* idx-1-k in ring */
1329 0 : ulong ri = (gui->summary.accdb_win_idx + FD_GUI_ACCDB_WIN_SAMPLES - 1UL - k) % FD_GUI_ACCDB_WIN_SAMPLES;
1330 0 : weighted_dt += w * (double)gui->summary.accdb_win_dt_nanos[ ri ] / 1e9;
1331 0 : }
1332 :
1333 : /* Helper: weighted rate of a delta ring. */
1334 0 : # define WRATE( ring ) ( fd_gui_accdb_weighted_rate( (ring), gui->summary.accdb_win_idx, n, weighted_dt ) )
1335 :
1336 0 : double agg_acquired_rate = WRATE( gui->summary.agg_acquired_win );
1337 0 : double agg_acquired_writable_rate = WRATE( gui->summary.agg_acquired_writable_win );
1338 0 : double agg_bytes_read_rate = WRATE( gui->summary.agg_bytes_read_win );
1339 0 : double agg_bytes_copied_rate = WRATE( gui->summary.agg_bytes_copied_win );
1340 0 : double agg_bytes_written_rate = WRATE( gui->summary.agg_bytes_written_win );
1341 0 : double agg_bytes_written_accdb_rate = WRATE( gui->summary.agg_bytes_written_accdb_win );
1342 0 : double agg_read_ops_rate = WRATE( gui->summary.agg_read_ops_win );
1343 0 : double agg_write_ops_rate = WRATE( gui->summary.agg_write_ops_win );
1344 0 : double agg_relocated_bytes_rate = WRATE( gui->summary.agg_relocated_bytes_win );
1345 0 : double agg_misses_rate = WRATE( gui->summary.agg_misses_win );
1346 :
1347 0 : double agg_hit_rate = agg_acquired_rate>0.0
1348 0 : ? fmax( 0.0, 1.0 - agg_misses_rate / agg_acquired_rate )
1349 0 : : 0.0;
1350 :
1351 :
1352 0 : jsonp_open_envelope( gui->http, "accounts", "stats" );
1353 0 : jsonp_open_object( gui->http, "value" );
1354 0 : jsonp_long( gui->http, "sample_time_nanos", cur->sample_time_nanos );
1355 :
1356 0 : jsonp_open_object( gui->http, "disk" );
1357 0 : jsonp_ulong( gui->http, "accounts_total", cur->accounts_total );
1358 0 : jsonp_ulong( gui->http, "accounts_capacity", cur->accounts_capacity );
1359 0 : jsonp_ulong( gui->http, "allocated_bytes", cur->disk_allocated_bytes );
1360 0 : jsonp_ulong( gui->http, "current_bytes", cur->disk_current_bytes );
1361 0 : jsonp_ulong( gui->http, "used_bytes", cur->disk_used_bytes );
1362 0 : jsonp_close_object( gui->http );
1363 :
1364 0 : jsonp_open_object( gui->http, "compaction" );
1365 0 : jsonp_ulong( gui->http, "in_compaction", cur->in_compaction );
1366 0 : jsonp_ulong( gui->http, "compactions_requested", cur->compactions_requested );
1367 0 : jsonp_ulong( gui->http, "compactions_completed", cur->compactions_completed );
1368 0 : jsonp_ulong( gui->http, "accounts_relocated_bytes", cur->accounts_relocated_bytes );
1369 0 : jsonp_double( gui->http, "relocated_bytes_per_sec", agg_relocated_bytes_rate );
1370 0 : jsonp_close_object( gui->http );
1371 :
1372 0 : ulong cache_size_bytes = 0UL;
1373 0 : ulong gui_tile_idx = fd_topo_find_tile( gui->topo, "gui", 0UL );
1374 0 : if( FD_LIKELY( gui_tile_idx!=ULONG_MAX ) ) {
1375 0 : cache_size_bytes = gui->topo->tiles[ gui_tile_idx ].gui.cache_size_gib * (1UL<<30);
1376 0 : }
1377 :
1378 0 : jsonp_open_object( gui->http, "cache" );
1379 0 : jsonp_double( gui->http, "hit_rate_ema", agg_hit_rate );
1380 0 : jsonp_ulong( gui->http, "size_bytes", cache_size_bytes );
1381 :
1382 0 : jsonp_open_array( gui->http, "classes" );
1383 0 : for( ulong c=0UL; c<FD_ACCDB_CACHE_CLASS_CNT; c++ ) {
1384 0 : jsonp_open_object( gui->http, NULL );
1385 0 : jsonp_ulong( gui->http, "class", c );
1386 0 : jsonp_ulong( gui->http, "used_slots", cur->cache_class_used [ c ] );
1387 0 : jsonp_ulong( gui->http, "max_slots", cur->cache_class_max [ c ] );
1388 0 : jsonp_ulong( gui->http, "reserved_slots", cur->cache_class_reserved [ c ] );
1389 0 : jsonp_ulong( gui->http, "target_used_slots", cur->cache_class_target_used [ c ] );
1390 0 : jsonp_ulong( gui->http, "low_water_used_slots", cur->cache_class_low_water_used [ c ] );
1391 0 : jsonp_ulong( gui->http, "not_found", cur->not_found_per_class [ c ] );
1392 0 : jsonp_ulong( gui->http, "evicted", cur->evicted_per_class [ c ] );
1393 0 : jsonp_ulong( gui->http, "preevicted", cur->preevicted_per_class [ c ] );
1394 0 : jsonp_ulong( gui->http, "committed_new", cur->committed_new_per_class [ c ] );
1395 0 : jsonp_ulong( gui->http, "committed_overwrite", cur->committed_overwrite_per_class [ c ] );
1396 0 : double acq_rate = WRATE( gui->summary.class_acq_win [ c ] );
1397 0 : double acq_wr_rate = WRATE( gui->summary.class_acq_wr_win [ c ] );
1398 0 : double nf_rate = WRATE( gui->summary.class_not_found_win [ c ] );
1399 0 : jsonp_double( gui->http, "not_found_per_sec", nf_rate );
1400 0 : jsonp_double( gui->http, "evicted_per_sec", WRATE( gui->summary.class_evicted_win [ c ] ) );
1401 0 : jsonp_double( gui->http, "preevicted_per_sec", WRATE( gui->summary.class_preevicted_win [ c ] ) );
1402 0 : jsonp_double( gui->http, "committed_new_per_sec", WRATE( gui->summary.class_commit_new_win [ c ] ) );
1403 0 : jsonp_double( gui->http, "committed_overwrite_per_sec", WRATE( gui->summary.class_commit_over_win[ c ] ) );
1404 : /* reads_per_sec = acquired - acquired_writable (per class);
1405 : writes_per_sec = acquired_writable (per class). */
1406 0 : jsonp_double( gui->http, "reads_per_sec", fmax( 0.0, acq_rate - acq_wr_rate ) );
1407 0 : jsonp_double( gui->http, "writes_per_sec", acq_wr_rate );
1408 0 : jsonp_double( gui->http, "hit_rate_ema",
1409 0 : acq_rate>0.0 ? fmax( 0.0, 1.0 - nf_rate / acq_rate ) : 0.0 );
1410 0 : jsonp_close_object( gui->http );
1411 0 : }
1412 0 : jsonp_close_array( gui->http );
1413 0 : jsonp_close_object( gui->http );
1414 :
1415 : /* Per-tile breakdown. Iterate the slot table built at init.
1416 : snapwr's row disappears when it has reached the shutdown
1417 : status (matching how snapwr drops out of the overview tiles
1418 : table). */
1419 0 : jsonp_open_array( gui->http, "tiles" );
1420 0 : for( ulong s=0UL; s<gui->summary.accdb_tile_cnt; s++ ) {
1421 0 : ulong t_idx = (ulong)gui->summary.accdb_tile_topo_idx[ s ];
1422 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ t_idx ];
1423 0 : uchar kind = gui->summary.accdb_tile_kind[ s ];
1424 :
1425 0 : if( kind==FD_GUI_ACCDB_TILE_KIND_SNAPWR && gui->summary.tile_cur_status[ s ]==2U ) continue;
1426 :
1427 0 : double t_acq_rate = WRATE( gui->summary.tile_acquired_win [ s ] );
1428 0 : double t_acq_wr_rate = WRATE( gui->summary.tile_acquired_writable_win[ s ] );
1429 0 : double t_br_rate = WRATE( gui->summary.tile_bytes_read_win [ s ] );
1430 0 : double t_bc_rate = WRATE( gui->summary.tile_bytes_copied_win [ s ] );
1431 0 : double t_bw_rate = WRATE( gui->summary.tile_bytes_written_win [ s ] );
1432 0 : double t_ro_rate = WRATE( gui->summary.tile_read_ops_win [ s ] );
1433 0 : double t_wo_rate = WRATE( gui->summary.tile_write_ops_win [ s ] );
1434 0 : double t_nf_rate = WRATE( gui->summary.tile_misses_win [ s ] );
1435 0 : double t_ev_rate = WRATE( gui->summary.tile_evicted_win [ s ] );
1436 0 : double t_cm_rate = WRATE( gui->summary.tile_committed_win [ s ] );
1437 0 : double t_ac_rate = WRATE( gui->summary.tile_acquire_calls_win [ s ] );
1438 :
1439 0 : char const * joiner;
1440 0 : switch( kind ) {
1441 0 : case FD_GUI_ACCDB_TILE_KIND_RW: joiner = "RW"; break;
1442 0 : case FD_GUI_ACCDB_TILE_KIND_SNAPWR: joiner = "RW"; break;
1443 0 : case FD_GUI_ACCDB_TILE_KIND_ACCDB: joiner = "RW"; break;
1444 0 : default: joiner = "RO"; break;
1445 0 : }
1446 :
1447 0 : jsonp_open_object( gui->http, NULL );
1448 0 : jsonp_string( gui->http, "name", tile->name );
1449 0 : jsonp_ulong( gui->http, "kind_id", tile->kind_id );
1450 0 : jsonp_string( gui->http, "joiner_type", joiner );
1451 0 : jsonp_ulong( gui->http, "status", (ulong)gui->summary.tile_cur_status[ s ] );
1452 :
1453 : /* Lifetime totals. */
1454 0 : jsonp_ulong( gui->http, "acquired", gui->summary.tile_cur_acquired [ s ] );
1455 0 : jsonp_ulong( gui->http, "bytes_read", gui->summary.tile_cur_bytes_read [ s ] );
1456 0 : jsonp_ulong( gui->http, "bytes_written", gui->summary.tile_cur_bytes_written [ s ] );
1457 :
1458 : /* Rates. */
1459 0 : jsonp_double( gui->http, "acquired_per_sec", t_acq_rate );
1460 0 : jsonp_double( gui->http, "acquired_writable_per_sec", t_acq_wr_rate );
1461 0 : jsonp_double( gui->http, "bytes_read_per_sec", t_br_rate );
1462 0 : jsonp_double( gui->http, "bytes_copied_per_sec", t_bc_rate );
1463 0 : jsonp_double( gui->http, "bytes_written_per_sec", t_bw_rate );
1464 0 : jsonp_double( gui->http, "read_ops_per_sec", t_ro_rate );
1465 0 : jsonp_double( gui->http, "write_ops_per_sec", t_wo_rate );
1466 0 : jsonp_double( gui->http, "not_found_per_sec", t_nf_rate );
1467 0 : jsonp_double( gui->http, "evicted_per_sec", t_ev_rate );
1468 0 : jsonp_double( gui->http, "committed_per_sec", t_cm_rate );
1469 0 : jsonp_double( gui->http, "acquire_calls_per_sec", t_ac_rate );
1470 :
1471 0 : jsonp_double( gui->http, "hit_rate_ema",
1472 0 : t_acq_rate>0.0 ? fmax( 0.0, 1.0 - t_nf_rate / t_acq_rate ) : 0.0 );
1473 :
1474 : /* 60-second sparkline history. Emit oldest-first so the
1475 : frontend treats index 0 as the leftmost (oldest) sample. */
1476 0 : ulong sp_cnt = gui->summary.tile_sparkline_count[ s ];
1477 0 : jsonp_open_array( gui->http, "acquired_history" );
1478 0 : for( ulong k=0UL; k<sp_cnt; k++ ) {
1479 0 : ulong idx = sp_cnt - 1UL - k;
1480 0 : jsonp_double( gui->http, NULL, gui->summary.tile_sparkline_acq_history[ s ][ idx ] );
1481 0 : }
1482 0 : jsonp_close_array( gui->http );
1483 0 : jsonp_open_array( gui->http, "acquired_writable_history" );
1484 0 : for( ulong k=0UL; k<sp_cnt; k++ ) {
1485 0 : ulong idx = sp_cnt - 1UL - k;
1486 0 : jsonp_double( gui->http, NULL, gui->summary.tile_sparkline_acq_wr_history[ s ][ idx ] );
1487 0 : }
1488 0 : jsonp_close_array( gui->http );
1489 0 : jsonp_close_object( gui->http );
1490 0 : }
1491 0 : jsonp_close_array( gui->http );
1492 :
1493 0 : jsonp_open_object( gui->http, "io" );
1494 0 : jsonp_ulong( gui->http, "acquired", cur->acquired );
1495 0 : jsonp_ulong( gui->http, "acquired_writable", cur->acquired_writable );
1496 0 : jsonp_ulong( gui->http, "bytes_read", cur->bytes_read );
1497 0 : jsonp_ulong( gui->http, "bytes_copied", cur->bytes_copied );
1498 0 : jsonp_ulong( gui->http, "bytes_written", cur->bytes_written );
1499 0 : jsonp_ulong( gui->http, "bytes_written_accdb", cur->bytes_written_accdb );
1500 0 : jsonp_ulong( gui->http, "read_ops", cur->read_ops );
1501 0 : jsonp_ulong( gui->http, "write_ops", cur->write_ops );
1502 0 : jsonp_double( gui->http, "acquired_per_sec", agg_acquired_rate );
1503 0 : jsonp_double( gui->http, "acquired_writable_per_sec", agg_acquired_writable_rate );
1504 0 : jsonp_double( gui->http, "bytes_read_per_sec", agg_bytes_read_rate );
1505 0 : jsonp_double( gui->http, "bytes_copied_per_sec", agg_bytes_copied_rate );
1506 0 : jsonp_double( gui->http, "bytes_written_per_sec", agg_bytes_written_rate );
1507 0 : jsonp_double( gui->http, "read_ops_per_sec", agg_read_ops_rate );
1508 0 : jsonp_double( gui->http, "write_ops_per_sec", agg_write_ops_rate );
1509 : /* Prewrite ratio: fraction of bytes written that came from the
1510 : accdb tile's background work (preevict + compaction).
1511 : cur->bytes_written already includes accdb tile's writes, so
1512 : the ratio is just accdb_rate / bytes_written_rate. */
1513 0 : jsonp_double( gui->http, "prewrite_ratio",
1514 0 : agg_bytes_written_rate>0.0
1515 0 : ? fmin( 1.0, agg_bytes_written_accdb_rate / agg_bytes_written_rate )
1516 0 : : 0.0 );
1517 0 : jsonp_close_object( gui->http );
1518 :
1519 : /* Per-partition table. Only emit partitions that have been
1520 : written to (skip the cold tail of the pool that has never been
1521 : allocated). Ticks are converted to wallclock nanoseconds using
1522 : the GUI tile's locally-measured tick rate, since the accdb hot
1523 : path stamps fd_tickcount() rather than fd_log_wallclock() (no
1524 : syscall on the IO path). */
1525 0 : jsonp_open_array( gui->http, "partitions" );
1526 0 : if( FD_LIKELY( gui->accdb_shmem ) ) {
1527 0 : ulong partition_sz = fd_accdb_shmem_partition_sz( gui->accdb_shmem );
1528 0 : long now_ticks = (long)fd_tickcount();
1529 0 : double tick_per_ns = gui->tick_per_ns;
1530 0 : for( ulong p=0UL; p<gui->summary.partition_cnt; p++ ) {
1531 0 : fd_accdb_shmem_partition_info_t const * info = &gui->summary.partitions[ p ];
1532 : /* Skip partitions that have never been written and are not
1533 : currently in any compaction state. */
1534 0 : if( !info->bytes_written && !info->compaction_state ) continue;
1535 :
1536 0 : double read_ops_rate = WRATE( gui->summary.partition_read_ops_win [ p ] );
1537 0 : double bytes_read_rate = WRATE( gui->summary.partition_bytes_read_win [ p ] );
1538 0 : double write_ops_rate = WRATE( gui->summary.partition_write_ops_win [ p ] );
1539 0 : double bytes_written_rate= WRATE( gui->summary.partition_bytes_written_win[p ] );
1540 :
1541 0 : double age_seconds = 0.0;
1542 0 : double filled_seconds = 0.0;
1543 0 : if( info->created_ticks && tick_per_ns>0.0 ) {
1544 0 : age_seconds = ((double)(now_ticks - info->created_ticks)) / tick_per_ns / 1e9;
1545 0 : if( age_seconds<0.0 ) age_seconds = 0.0;
1546 0 : }
1547 0 : if( info->filled_ticks && tick_per_ns>0.0 ) {
1548 0 : filled_seconds = ((double)(now_ticks - info->filled_ticks )) / tick_per_ns / 1e9;
1549 0 : if( filled_seconds<0.0 ) filled_seconds = 0.0;
1550 0 : }
1551 :
1552 : /* Fully compacted, awaiting reclaim: present as an "Off" tier
1553 : with zeroed utilization so the row visually clears once its
1554 : data has been moved out. */
1555 0 : int is_compacted = info->compaction_state==0 &&
1556 0 : info->write_offset>0UL &&
1557 0 : info->compaction_offset>=info->write_offset;
1558 0 : ulong tier = is_compacted ? 255UL : (ulong)info->layer;
1559 0 : double utilization = (!is_compacted && partition_sz)
1560 0 : ? (double)info->write_offset / (double)partition_sz : 0.0;
1561 0 : double fragmentation = (!is_compacted && info->write_offset)
1562 0 : ? (double)info->bytes_freed / (double)info->write_offset : 0.0;
1563 0 : ulong used_bytes = (!is_compacted && info->write_offset > info->bytes_freed)
1564 0 : ? info->write_offset - info->bytes_freed : 0UL;
1565 0 : double used_frac = partition_sz ? (double)used_bytes / (double)partition_sz : 0.0;
1566 0 : double fragmented_frac= (!is_compacted && partition_sz) ? (double)info->bytes_freed / (double)partition_sz : 0.0;
1567 0 : double compaction_frac= (!is_compacted && partition_sz) ? (double)info->compaction_offset / (double)partition_sz : 0.0;
1568 :
1569 0 : jsonp_open_object( gui->http, NULL );
1570 0 : jsonp_ulong( gui->http, "partition_idx", p );
1571 0 : jsonp_ulong( gui->http, "file_offset", info->file_offset );
1572 0 : jsonp_ulong( gui->http, "tier", tier );
1573 0 : jsonp_ulong( gui->http, "write_offset", info->write_offset );
1574 0 : jsonp_ulong( gui->http, "bytes_freed", info->bytes_freed );
1575 0 : jsonp_ulong( gui->http, "read_ops", info->read_ops );
1576 0 : jsonp_ulong( gui->http, "bytes_read", info->bytes_read );
1577 0 : jsonp_ulong( gui->http, "write_ops", info->write_ops );
1578 0 : jsonp_ulong( gui->http, "bytes_written", info->bytes_written );
1579 0 : jsonp_double( gui->http, "read_ops_per_sec", read_ops_rate );
1580 0 : jsonp_double( gui->http, "bytes_read_per_sec", bytes_read_rate );
1581 0 : jsonp_double( gui->http, "write_ops_per_sec", write_ops_rate );
1582 0 : jsonp_double( gui->http, "bytes_written_per_sec",bytes_written_rate );
1583 0 : jsonp_double( gui->http, "utilization", utilization );
1584 0 : jsonp_double( gui->http, "fragmentation", fragmentation );
1585 0 : jsonp_double( gui->http, "used_frac", used_frac );
1586 0 : jsonp_double( gui->http, "fragmented_frac", fragmented_frac );
1587 0 : jsonp_double( gui->http, "compaction_trigger_frac", 0.30 );
1588 0 : jsonp_double( gui->http, "age_seconds", age_seconds );
1589 0 : jsonp_double( gui->http, "filled_seconds", filled_seconds );
1590 0 : jsonp_ulong( gui->http, "compaction_state", (ulong)info->compaction_state );
1591 0 : jsonp_double( gui->http, "compaction_frac", compaction_frac );
1592 0 : jsonp_bool( gui->http, "is_write_head", (int)info->is_write_head );
1593 0 : jsonp_close_object( gui->http );
1594 0 : }
1595 0 : }
1596 0 : jsonp_close_array( gui->http );
1597 :
1598 0 : jsonp_close_object( gui->http );
1599 0 : jsonp_close_envelope( gui->http );
1600 :
1601 0 : # undef WRATE
1602 0 : }
1603 :
1604 : static int
1605 : fd_gui_gossip_contains( fd_gui_t const * gui,
1606 0 : uchar const * pubkey ) {
1607 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
1608 0 : if( FD_UNLIKELY( !memcmp( gui->gossip.peers[ i ].pubkey->uc, pubkey, 32 ) ) ) return 1;
1609 0 : }
1610 0 : return 0;
1611 0 : }
1612 :
1613 : static int
1614 : fd_gui_vote_acct_contains( fd_gui_t const * gui,
1615 0 : uchar const * pubkey ) {
1616 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
1617 0 : if( FD_UNLIKELY( !memcmp( gui->vote_account.vote_accounts[ i ].pubkey, pubkey, 32 ) ) ) return 1;
1618 0 : }
1619 0 : return 0;
1620 0 : }
1621 :
1622 : static void
1623 : fd_gui_printf_peer( fd_gui_t * gui,
1624 0 : uchar const * identity_pubkey ) {
1625 0 : ulong gossip_idx = ULONG_MAX;
1626 0 : ulong info_idx = ULONG_MAX;
1627 0 : ulong vote_idxs[ FD_GUI_MAX_PEER_CNT ] = {0};
1628 0 : ulong vote_idx_cnt = 0UL;
1629 :
1630 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
1631 0 : if( FD_UNLIKELY( !memcmp( gui->gossip.peers[ i ].pubkey->uc, identity_pubkey, 32 ) ) ) {
1632 0 : gossip_idx = i;
1633 0 : break;
1634 0 : }
1635 0 : }
1636 :
1637 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
1638 0 : if( FD_UNLIKELY( !memcmp( gui->validator_info.info[ i ].pubkey, identity_pubkey, 32 ) ) ) {
1639 0 : info_idx = i;
1640 0 : break;
1641 0 : }
1642 0 : }
1643 :
1644 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
1645 0 : if( FD_UNLIKELY( !memcmp( gui->vote_account.vote_accounts[ i ].pubkey, identity_pubkey, 32 ) ) ) {
1646 0 : vote_idxs[ vote_idx_cnt++ ] = i;
1647 0 : }
1648 0 : }
1649 :
1650 0 : jsonp_open_object( gui->http, NULL );
1651 :
1652 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1653 0 : fd_base58_encode_32( identity_pubkey, NULL, identity_base58 );
1654 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
1655 :
1656 0 : if( FD_UNLIKELY( gossip_idx==ULONG_MAX ) ) {
1657 0 : jsonp_string( gui->http, "gossip", NULL );
1658 0 : } else {
1659 0 : jsonp_open_object( gui->http, "gossip" );
1660 :
1661 0 : char version[ 64UL ];
1662 0 : FD_TEST( fd_gossip_version_cstr( gui->gossip.peers[ gossip_idx ].version.major, gui->gossip.peers[ gossip_idx ].version.minor, gui->gossip.peers[ gossip_idx ].version.patch, version, sizeof( version ) ) );
1663 0 : jsonp_string( gui->http, "version", version );
1664 0 : jsonp_null( gui->http, "client_id" ); /* TODO: Frankendancer support */
1665 0 : jsonp_ulong( gui->http, "feature_set", gui->gossip.peers[ gossip_idx ].version.feature_set );
1666 0 : jsonp_ulong( gui->http, "wallclock", gui->gossip.peers[ gossip_idx ].wallclock );
1667 0 : jsonp_ulong( gui->http, "shred_version", gui->gossip.peers[ gossip_idx ].shred_version );
1668 0 : jsonp_open_object( gui->http, "sockets" );
1669 0 : for( ulong j=0UL; j<12UL; j++ ) {
1670 0 : if( FD_LIKELY( !gui->gossip.peers[ gossip_idx ].sockets[ j ].ipv4 && !gui->gossip.peers[ gossip_idx ].sockets[ j ].port ) ) continue;
1671 0 : char const * tag;
1672 0 : switch( j ) {
1673 0 : case 0: tag = "gossip"; break;
1674 0 : case 1: tag = "rpc"; break;
1675 0 : case 2: tag = "rpc_pubsub"; break;
1676 0 : case 3: tag = "serve_repair"; break;
1677 0 : case 4: tag = "serve_repair_quic"; break;
1678 0 : case 5: tag = "tpu"; break;
1679 0 : case 6: tag = "tpu_quic"; break;
1680 0 : case 7: tag = "tvu"; break;
1681 0 : case 8: tag = "tvu_quic"; break;
1682 0 : case 9: tag = "tpu_forwards"; break;
1683 0 : case 10: tag = "tpu_forwards_quic"; break;
1684 0 : case 11: tag = "tpu_vote"; break;
1685 0 : }
1686 0 : char line[ 64 ];
1687 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 ) );
1688 0 : jsonp_string( gui->http, tag, line );
1689 0 : }
1690 0 : jsonp_close_object( gui->http );
1691 :
1692 0 : jsonp_close_object( gui->http );
1693 0 : }
1694 :
1695 0 : jsonp_open_array( gui->http, "vote" );
1696 0 : ulong vote_idx_cnt_bounded = fd_ulong_min( vote_idx_cnt, 5UL );
1697 0 : for( ulong i=0UL; i<vote_idx_cnt_bounded; i++ ) {
1698 0 : jsonp_open_object( gui->http, NULL );
1699 0 : char vote_account_base58[ FD_BASE58_ENCODED_32_SZ ];
1700 0 : fd_base58_encode_32( gui->vote_account.vote_accounts[ vote_idxs[ i ] ].vote_account->uc, NULL, vote_account_base58 );
1701 0 : jsonp_string( gui->http, "vote_account", vote_account_base58 );
1702 0 : jsonp_ulong_as_str( gui->http, "activated_stake", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].activated_stake );
1703 0 : jsonp_ulong( gui->http, "last_vote", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].last_vote );
1704 0 : jsonp_ulong( gui->http, "root_slot", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].root_slot );
1705 0 : jsonp_ulong( gui->http, "epoch_credits", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].epoch_credits );
1706 0 : jsonp_ulong( gui->http, "commission", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].commission );
1707 0 : jsonp_bool( gui->http, "delinquent", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].delinquent );
1708 0 : jsonp_close_object( gui->http );
1709 0 : }
1710 0 : jsonp_close_array( gui->http );
1711 :
1712 0 : if( FD_UNLIKELY( info_idx==ULONG_MAX ) ) {
1713 0 : jsonp_string( gui->http, "info", NULL );
1714 0 : } else {
1715 0 : jsonp_open_object( gui->http, "info" );
1716 0 : jsonp_string( gui->http, "name", gui->validator_info.info[ info_idx ].name );
1717 0 : jsonp_string( gui->http, "details", gui->validator_info.info[ info_idx ].details );
1718 0 : jsonp_string( gui->http, "website", gui->validator_info.info[ info_idx ].website );
1719 0 : jsonp_string( gui->http, "icon_url", gui->validator_info.info[ info_idx ].icon_uri );
1720 0 : jsonp_string( gui->http, "keybase_username", "" );
1721 0 : jsonp_close_object( gui->http );
1722 0 : }
1723 :
1724 0 : jsonp_close_object( gui->http );
1725 0 : }
1726 :
1727 : static void
1728 : peers_printf_node( fd_gui_peers_ctx_t * peers,
1729 0 : ulong contact_info_table_idx ) {
1730 0 : fd_gui_peers_node_t * peer = &peers->contact_info_table[ contact_info_table_idx ];
1731 :
1732 0 : jsonp_open_object( peers->http, NULL );
1733 :
1734 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1735 0 : fd_base58_encode_32( peer->row.pubkey.uc, NULL, identity_base58 );
1736 0 : jsonp_string( peers->http, "identity_pubkey", identity_base58 );
1737 :
1738 0 : jsonp_open_object( peers->http, "gossip" );
1739 :
1740 0 : char version[ 64UL ];
1741 0 : FD_TEST( fd_gossip_version_cstr( peer->row.contact_info.version.major, peer->row.contact_info.version.minor, peer->row.contact_info.version.patch, version, sizeof( version ) ) );
1742 0 : jsonp_string( peers->http, "version", version );
1743 0 : jsonp_ulong( peers->http, "client_id", peer->row.contact_info.version.client );
1744 0 : jsonp_ulong( peers->http, "feature_set", peer->row.contact_info.version.feature_set );
1745 0 : jsonp_long( peers->http, "wallclock", peer->row.wallclock_nanos );
1746 0 : jsonp_ulong( peers->http, "shred_version", peer->row.contact_info.shred_version );
1747 0 : jsonp_open_object( peers->http, "sockets" );
1748 0 : for( ulong j=0UL; j<FD_GOSSIP_CONTACT_INFO_SOCKET_CNT; j++ ) {
1749 0 : char const * tag;
1750 0 : switch( j ) {
1751 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP: tag = "gossip"; break;
1752 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_SERVE_REPAIR_QUIC: tag = "serve_repair_quic"; break;
1753 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_RPC: tag = "rpc"; break;
1754 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_RPC_PUBSUB: tag = "rpc_pubsub"; break;
1755 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_SERVE_REPAIR: tag = "serve_repair"; break;
1756 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TPU: tag = "tpu"; break;
1757 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_FORWARDS: tag = "tpu_forwards"; break;
1758 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_FORWARDS_QUIC: tag = "tpu_forwards_quic"; break;
1759 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_QUIC: tag = "tpu_quic"; break;
1760 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_VOTE: tag = "tpu_vote"; break;
1761 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TVU: tag = "tvu"; break;
1762 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TVU_QUIC: tag = "tvu_quic"; break;
1763 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_TPU_VOTE_QUIC: tag = "tpu_vote_quic"; break;
1764 0 : case FD_GOSSIP_CONTACT_INFO_SOCKET_ALPENGLOW: tag = "alpenglow"; break;
1765 0 : default: tag = "unknown"; break;
1766 0 : }
1767 0 : uint ip4 = peer->row.contact_info.sockets[ j ].is_ipv6 ? 0U : peer->row.contact_info.sockets[ j ].ip4;
1768 0 : char line[ 64 ];
1769 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->row.contact_info.sockets[ j ].port ) ) );
1770 0 : jsonp_string( peers->http, tag, line );
1771 0 : }
1772 0 : jsonp_close_object( peers->http );
1773 :
1774 0 : if( FD_LIKELY( peer->row.country_code_idx!=UCHAR_MAX ) ) {
1775 0 : jsonp_string( peers->http, "country_code", peers->dbip.country_code[ peer->row.country_code_idx ] );
1776 0 : } else {
1777 0 : jsonp_null( peers->http, "country_code" );
1778 0 : }
1779 :
1780 0 : if( FD_LIKELY( peer->row.city_name_idx!=UINT_MAX ) ) {
1781 0 : jsonp_string( peers->http, "city_name", peers->dbip.city_name[ peer->row.city_name_idx ] );
1782 0 : } else {
1783 0 : jsonp_null( peers->http, "city_name" );
1784 0 : }
1785 :
1786 0 : jsonp_close_object( peers->http );
1787 :
1788 0 : if( FD_LIKELY( !peer->row.has_vote_info ) ) {
1789 0 : jsonp_open_array( peers->http, "vote" );
1790 0 : jsonp_close_array( peers->http );
1791 0 : } else {
1792 0 : jsonp_open_array( peers->http, "vote" );
1793 0 : jsonp_open_object( peers->http, NULL );
1794 0 : char vote_account_base58[ FD_BASE58_ENCODED_32_SZ ];
1795 0 : fd_base58_encode_32( peer->row.vote_account.uc, NULL, vote_account_base58 );
1796 0 : jsonp_string( peers->http, "vote_account", vote_account_base58 );
1797 0 : jsonp_ulong_as_str( peers->http, "activated_stake", fd_ulong_if( peer->row.stake==ULONG_MAX, 0UL, peer->row.stake ) );
1798 0 : jsonp_ulong( peers->http, "last_vote", 0UL ); /* todo: deprecate */
1799 0 : jsonp_ulong( peers->http, "epoch_credits", 0UL ); /* todo: deprecate */
1800 0 : jsonp_ulong( peers->http, "commission", 0UL ); /* todo: deprecate */
1801 0 : jsonp_ulong( peers->http, "root_slot", 0UL ); /* todo: deprecate */
1802 0 : jsonp_bool( peers->http, "delinquent", peer->row.delinquent );
1803 0 : jsonp_close_object( peers->http );
1804 0 : jsonp_close_array( peers->http );
1805 0 : }
1806 :
1807 0 : fd_gui_config_parse_info_t * node_info = fd_gui_peers_node_info_map_ele_query( peers->node_info_map, &peer->row.pubkey, NULL, peers->node_info_pool );
1808 0 : if( FD_UNLIKELY( !node_info ) ) {
1809 0 : jsonp_string( peers->http, "info", NULL );
1810 0 : } else {
1811 0 : jsonp_open_object( peers->http, "info" );
1812 0 : jsonp_string( peers->http, "name", node_info->name );
1813 0 : jsonp_string( peers->http, "details", node_info->details );
1814 0 : jsonp_string( peers->http, "website", node_info->website );
1815 0 : jsonp_string( peers->http, "icon_url", node_info->icon_uri );
1816 0 : jsonp_string( peers->http, "keybase_username", node_info->keybase_username );
1817 0 : jsonp_close_object( peers->http );
1818 0 : }
1819 :
1820 0 : jsonp_close_object( peers->http );
1821 0 : }
1822 :
1823 : void
1824 : fd_gui_peers_printf_nodes( fd_gui_peers_ctx_t * peers,
1825 : int * actions,
1826 : ulong * idxs,
1827 0 : ulong count ) {
1828 0 : jsonp_open_envelope( peers->http, "peers", "update" );
1829 0 : jsonp_open_object( peers->http, "value" );
1830 0 : jsonp_open_array( peers->http, "add" );
1831 0 : for( ulong i=0UL; i<count; i++ ) if( FD_UNLIKELY( actions[ i ]==FD_GUI_PEERS_NODE_ADD ) ) peers_printf_node( peers, idxs[ i ] );
1832 0 : jsonp_close_array( peers->http );
1833 :
1834 0 : jsonp_open_array( peers->http, "update" );
1835 0 : for( ulong i=0UL; i<count; i++ ) if( FD_UNLIKELY( actions[ i ]==FD_GUI_PEERS_NODE_UPDATE ) ) peers_printf_node( peers, idxs[ i ] );
1836 0 : jsonp_close_array( peers->http );
1837 :
1838 0 : jsonp_open_array( peers->http, "remove" );
1839 0 : for( ulong i=0UL; i<count; i++ ) {
1840 0 : if( FD_UNLIKELY( actions[ i ]==FD_GUI_PEERS_NODE_DELETE ) ) {
1841 0 : jsonp_open_object( peers->http, NULL );
1842 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1843 0 : fd_base58_encode_32( peers->contact_info_table[ idxs[ i ] ].row.pubkey.uc, NULL, identity_base58 );
1844 0 : jsonp_string( peers->http, "identity_pubkey", identity_base58 );
1845 0 : jsonp_close_object( peers->http );
1846 0 : }
1847 0 : }
1848 0 : jsonp_close_array( peers->http );
1849 0 : jsonp_close_object( peers->http );
1850 0 : jsonp_close_envelope( peers->http );
1851 0 : }
1852 :
1853 : void
1854 0 : fd_gui_peers_printf_node_all( fd_gui_peers_ctx_t * peers ) {
1855 0 : jsonp_open_envelope( peers->http, "peers", "update" );
1856 0 : jsonp_open_object( peers->http, "value" );
1857 0 : jsonp_open_array( peers->http, "add" );
1858 : /* We can iter through the bandwidth tracking table since it will always be populated */
1859 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 );
1860 0 : !fd_gui_peers_bandwidth_tracking_fwd_iter_done( iter );
1861 0 : iter = fd_gui_peers_bandwidth_tracking_fwd_iter_next( iter, peers->contact_info_table ) ) {
1862 0 : ulong contact_info_table_idx = fd_gui_peers_bandwidth_tracking_fwd_iter_idx( iter );
1863 0 : peers_printf_node( peers, contact_info_table_idx );
1864 0 : }
1865 0 : jsonp_close_array( peers->http );
1866 0 : jsonp_open_array( peers->http, "update" );
1867 0 : jsonp_close_array( peers->http );
1868 0 : jsonp_open_array( peers->http, "remove" );
1869 0 : jsonp_close_array( peers->http );
1870 0 : jsonp_close_object( peers->http );
1871 0 : jsonp_close_envelope( peers->http );
1872 0 : }
1873 :
1874 : void
1875 0 : fd_gui_printf_peers_all( fd_gui_t * gui ) {
1876 0 : jsonp_open_envelope( gui->http, "peers", "update" );
1877 0 : jsonp_open_object( gui->http, "value" );
1878 0 : jsonp_open_array( gui->http, "add" );
1879 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
1880 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ i ].pubkey->uc );
1881 0 : }
1882 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
1883 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ i ].pubkey->uc );
1884 0 : if( FD_UNLIKELY( actually_added ) ) {
1885 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ i ].pubkey->uc );
1886 0 : }
1887 0 : }
1888 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
1889 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ i ].pubkey->uc ) &&
1890 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ i ].pubkey->uc );
1891 0 : if( FD_UNLIKELY( actually_added ) ) {
1892 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ i ].pubkey->uc );
1893 0 : }
1894 0 : }
1895 0 : jsonp_close_array( gui->http );
1896 0 : jsonp_close_object( gui->http );
1897 0 : jsonp_close_envelope( gui->http );
1898 0 : }
1899 :
1900 : static void
1901 : fd_gui_printf_ts_tile_timers( fd_gui_t * gui,
1902 : fd_gui_tile_timers_t const * prev,
1903 0 : fd_gui_tile_timers_t const * cur ) {
1904 0 : jsonp_open_object( gui->http, NULL );
1905 0 : jsonp_ulong_as_str( gui->http, "timestamp_nanos", 0 );
1906 0 : jsonp_open_array( gui->http, "tile_timers" );
1907 0 : fd_gui_printf_tile_timers( gui, prev, cur );
1908 0 : jsonp_close_array( gui->http );
1909 0 : jsonp_close_object( gui->http );
1910 0 : }
1911 :
1912 : void
1913 : fd_gui_printf_slot( fd_gui_t * gui,
1914 0 : ulong _slot ) {
1915 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
1916 :
1917 0 : char const * level;
1918 0 : switch( slot->level ) {
1919 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1920 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1921 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1922 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1923 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1924 0 : default: level = "unknown"; break;
1925 0 : }
1926 :
1927 0 : fd_gui_slot_t * parent_slot = fd_gui_get_slot( gui, slot->parent_slot );
1928 0 : long duration_nanos = LONG_MAX;
1929 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1930 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1931 0 : }
1932 :
1933 0 : jsonp_open_envelope( gui->http, "slot", "update" );
1934 0 : jsonp_open_object( gui->http, "value" );
1935 0 : fd_gui_leader_slot_t * lslot = fd_gui_get_leader_slot( gui, _slot );
1936 0 : jsonp_open_object( gui->http, "publish" );
1937 0 : jsonp_ulong( gui->http, "slot", _slot );
1938 0 : jsonp_bool( gui->http, "mine", slot->mine );
1939 0 : if( FD_UNLIKELY( slot->vote_slot!=ULONG_MAX ) ) jsonp_ulong( gui->http, "vote_slot", slot->vote_slot );
1940 0 : else jsonp_null( gui->http, "vote_slot" );
1941 0 : if( FD_UNLIKELY( slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, "vote_latency", slot->vote_latency );
1942 0 : else jsonp_null( gui->http, "vote_latency" );
1943 :
1944 0 : if( FD_UNLIKELY( lslot && lslot->leader_start_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
1945 0 : else jsonp_null ( gui->http, "start_timestamp_nanos" );
1946 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 );
1947 0 : else jsonp_null ( gui->http, "target_end_timestamp_nanos" );
1948 :
1949 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1950 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1951 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1952 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1953 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
1954 0 : jsonp_string( gui->http, "level", level );
1955 0 : if( FD_UNLIKELY( slot->nonvote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1956 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->nonvote_success );
1957 0 : if( FD_UNLIKELY( slot->nonvote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1958 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed );
1959 0 : if( FD_UNLIKELY( slot->vote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1960 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_success );
1961 0 : if( FD_UNLIKELY( slot->vote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1962 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->vote_failed );
1963 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1964 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1965 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1966 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1967 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
1968 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
1969 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1970 0 : else jsonp_ulong_as_str( gui->http, "transaction_fee", slot->transaction_fee );
1971 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1972 0 : else jsonp_ulong_as_str( gui->http, "priority_fee", slot->priority_fee );
1973 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1974 0 : else jsonp_ulong_as_str( gui->http, "tips", slot->tips );
1975 0 : jsonp_close_object( gui->http );
1976 0 : jsonp_close_object( gui->http );
1977 0 : jsonp_close_envelope( gui->http );
1978 0 : }
1979 :
1980 : void
1981 : fd_gui_printf_summary_ping( fd_gui_t * gui,
1982 0 : ulong id ) {
1983 0 : jsonp_open_envelope( gui->http, "summary", "ping" );
1984 0 : jsonp_ulong( gui->http, "id", id );
1985 0 : jsonp_null( gui->http, "value" );
1986 0 : jsonp_close_envelope( gui->http );
1987 0 : }
1988 :
1989 : void
1990 : fd_gui_printf_slot_rankings_request( fd_gui_t * gui,
1991 : ulong id,
1992 0 : int mine ) {
1993 0 : ulong epoch = ULONG_MAX;
1994 0 : for( ulong i = 0UL; i<2UL; i++ ) {
1995 0 : if( FD_LIKELY( gui->epoch.has_epoch[ i ] ) ) {
1996 : /* the "current" epoch is the smallest */
1997 0 : epoch = fd_ulong_min( epoch, gui->epoch.epochs[ i ].epoch );
1998 0 : }
1999 0 : }
2000 0 : ulong epoch_idx = epoch % 2UL;
2001 :
2002 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 );
2003 :
2004 0 : jsonp_open_envelope( gui->http, "slot", "query_rankings" );
2005 0 : jsonp_ulong( gui->http, "id", id );
2006 0 : jsonp_open_object( gui->http, "value" );
2007 :
2008 0 : #define OUTPUT_RANKING_ARRAY(field) \
2009 0 : jsonp_open_array( gui->http, "slots_" FD_STRINGIFY(field) ); \
2010 0 : for( ulong i = 0UL; i<fd_ulong_if( epoch==ULONG_MAX, 0UL, FD_GUI_SLOT_RANKINGS_SZ ); i++ ) { \
2011 0 : if( FD_UNLIKELY( rankings->field[ i ].slot==ULONG_MAX ) ) break; \
2012 0 : jsonp_ulong( gui->http, NULL, rankings->field[ i ].slot ); \
2013 0 : } \
2014 0 : jsonp_close_array( gui->http ); \
2015 0 : jsonp_open_array( gui->http, "vals_" FD_STRINGIFY(field) ); \
2016 0 : for( ulong i = 0UL; i<fd_ulong_if( epoch==ULONG_MAX, 0UL, FD_GUI_SLOT_RANKINGS_SZ ); i++ ) { \
2017 0 : if( FD_UNLIKELY( rankings->field[ i ].slot==ULONG_MAX ) ) break; \
2018 0 : jsonp_ulong( gui->http, NULL, rankings->field[ i ].value ); \
2019 0 : } \
2020 0 : jsonp_close_array( gui->http )
2021 :
2022 0 : OUTPUT_RANKING_ARRAY( largest_tips );
2023 0 : OUTPUT_RANKING_ARRAY( largest_fees );
2024 0 : OUTPUT_RANKING_ARRAY( largest_rewards );
2025 0 : OUTPUT_RANKING_ARRAY( largest_rewards_per_cu );
2026 0 : OUTPUT_RANKING_ARRAY( largest_duration );
2027 0 : OUTPUT_RANKING_ARRAY( largest_compute_units );
2028 0 : OUTPUT_RANKING_ARRAY( largest_skipped );
2029 0 : OUTPUT_RANKING_ARRAY( smallest_tips );
2030 0 : OUTPUT_RANKING_ARRAY( smallest_fees );
2031 0 : OUTPUT_RANKING_ARRAY( smallest_rewards );
2032 0 : OUTPUT_RANKING_ARRAY( smallest_rewards_per_cu );
2033 0 : OUTPUT_RANKING_ARRAY( smallest_duration );
2034 0 : OUTPUT_RANKING_ARRAY( smallest_compute_units );
2035 0 : OUTPUT_RANKING_ARRAY( smallest_skipped );
2036 :
2037 0 : #undef OUTPUT_RANKING_ARRAY
2038 :
2039 0 : jsonp_close_object( gui->http );
2040 0 : jsonp_close_envelope( gui->http );
2041 0 : }
2042 :
2043 : void
2044 : fd_gui_printf_slot_request( fd_gui_t * gui,
2045 : ulong _slot,
2046 0 : ulong id ) {
2047 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
2048 :
2049 0 : char const * level;
2050 0 : switch( slot->level ) {
2051 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
2052 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
2053 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
2054 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
2055 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
2056 0 : default: level = "unknown"; break;
2057 0 : }
2058 :
2059 0 : fd_gui_slot_t * parent_slot = fd_gui_get_slot( gui, slot->parent_slot );
2060 0 : long duration_nanos = LONG_MAX;
2061 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
2062 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
2063 0 : }
2064 :
2065 0 : jsonp_open_envelope( gui->http, "slot", "query" );
2066 0 : jsonp_ulong( gui->http, "id", id );
2067 0 : jsonp_open_object( gui->http, "value" );
2068 0 : fd_gui_leader_slot_t * lslot = fd_gui_get_leader_slot( gui, _slot );
2069 :
2070 0 : jsonp_open_object( gui->http, "publish" );
2071 0 : jsonp_ulong( gui->http, "slot", _slot );
2072 0 : jsonp_bool( gui->http, "mine", slot->mine );
2073 0 : if( FD_UNLIKELY( slot->vote_slot!=ULONG_MAX ) ) jsonp_ulong( gui->http, "vote_slot", slot->vote_slot );
2074 0 : else jsonp_null( gui->http, "vote_slot" );
2075 0 : if( FD_UNLIKELY( slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, "vote_latency", slot->vote_latency );
2076 0 : else jsonp_null( gui->http, "vote_latency" );
2077 :
2078 0 : if( FD_UNLIKELY( lslot && lslot->leader_start_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
2079 0 : else jsonp_null ( gui->http, "start_timestamp_nanos" );
2080 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 );
2081 0 : else jsonp_null ( gui->http, "target_end_timestamp_nanos" );
2082 :
2083 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
2084 0 : jsonp_string( gui->http, "level", level );
2085 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
2086 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
2087 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
2088 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
2089 0 : if( FD_UNLIKELY( slot->nonvote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
2090 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->nonvote_success );
2091 0 : if( FD_UNLIKELY( slot->nonvote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
2092 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed );
2093 0 : if( FD_UNLIKELY( slot->vote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
2094 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_success );
2095 0 : if( FD_UNLIKELY( slot->vote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
2096 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->vote_failed );
2097 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
2098 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
2099 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
2100 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
2101 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
2102 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
2103 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
2104 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
2105 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
2106 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
2107 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
2108 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
2109 0 : jsonp_close_object( gui->http );
2110 :
2111 0 : jsonp_close_object( gui->http );
2112 0 : jsonp_close_envelope( gui->http );
2113 0 : }
2114 :
2115 : void
2116 : fd_gui_printf_slot_transactions_request( fd_gui_t * gui,
2117 : ulong _slot,
2118 0 : ulong id ) {
2119 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
2120 :
2121 0 : char const * level;
2122 0 : switch( slot->level ) {
2123 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
2124 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
2125 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
2126 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
2127 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
2128 0 : default: level = "unknown"; break;
2129 0 : }
2130 :
2131 0 : fd_gui_slot_t * parent_slot = fd_gui_get_slot( gui, slot->parent_slot );
2132 0 : long duration_nanos = LONG_MAX;
2133 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
2134 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
2135 0 : }
2136 :
2137 0 : jsonp_open_envelope( gui->http, "slot", "query_transactions" );
2138 0 : jsonp_ulong( gui->http, "id", id );
2139 0 : jsonp_open_object( gui->http, "value" );
2140 0 : fd_gui_leader_slot_t * lslot = fd_gui_get_leader_slot( gui, _slot );
2141 :
2142 0 : jsonp_open_object( gui->http, "publish" );
2143 0 : jsonp_ulong( gui->http, "slot", _slot );
2144 0 : jsonp_bool( gui->http, "mine", slot->mine );
2145 0 : if( FD_UNLIKELY( slot->vote_slot!=ULONG_MAX ) ) jsonp_ulong( gui->http, "vote_slot", slot->vote_slot );
2146 0 : else jsonp_null( gui->http, "vote_slot" );
2147 0 : if( FD_UNLIKELY( slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, "vote_latency", slot->vote_latency );
2148 0 : else jsonp_null( gui->http, "vote_latency" );
2149 :
2150 0 : if( FD_UNLIKELY( lslot && lslot->leader_start_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
2151 0 : else jsonp_null ( gui->http, "start_timestamp_nanos" );
2152 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 );
2153 0 : else jsonp_null ( gui->http, "target_end_timestamp_nanos" );
2154 :
2155 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
2156 0 : jsonp_string( gui->http, "level", level );
2157 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
2158 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
2159 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
2160 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
2161 0 : if( FD_UNLIKELY( slot->nonvote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
2162 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->nonvote_success );
2163 0 : if( FD_UNLIKELY( slot->nonvote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
2164 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed );
2165 0 : if( FD_UNLIKELY( slot->vote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
2166 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_success );
2167 0 : if( FD_UNLIKELY( slot->vote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
2168 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->vote_failed );
2169 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
2170 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
2171 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
2172 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
2173 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
2174 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
2175 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
2176 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
2177 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
2178 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
2179 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
2180 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
2181 0 : jsonp_close_object( gui->http );
2182 :
2183 0 : if( FD_UNLIKELY( lslot && lslot->unbecame_leader ) ) {
2184 0 : jsonp_open_object( gui->http, "limits" );
2185 0 : jsonp_ulong( gui->http, "used_total_block_cost", lslot->scheduler_stats->limits_usage->block_cost );
2186 0 : jsonp_ulong( gui->http, "used_total_vote_cost", lslot->scheduler_stats->limits_usage->vote_cost );
2187 0 : jsonp_ulong( gui->http, "used_total_bytes", lslot->scheduler_stats->limits_usage->block_data_bytes );
2188 0 : jsonp_ulong( gui->http, "used_total_microblocks", lslot->scheduler_stats->limits_usage->microblocks );
2189 0 : jsonp_open_array( gui->http, "used_account_write_costs" );
2190 0 : for( ulong i = 0; i<FD_PACK_TOP_WRITERS_CNT; i++ ) {
2191 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;
2192 :
2193 0 : jsonp_open_object( gui->http, NULL );
2194 0 : char account_base58[ FD_BASE58_ENCODED_32_SZ ];
2195 0 : fd_base58_encode_32( lslot->scheduler_stats->limits_usage->top_writers[ i ].key.b, NULL, account_base58 );
2196 0 : jsonp_string( gui->http, "account", account_base58 );
2197 0 : jsonp_ulong( gui->http, "cost", lslot->scheduler_stats->limits_usage->top_writers[ i ].total_cost );
2198 0 : jsonp_close_object( gui->http );
2199 0 : }
2200 0 : jsonp_close_array( gui->http );
2201 :
2202 0 : jsonp_ulong( gui->http, "max_total_block_cost", lslot->scheduler_stats->limits->max_cost_per_block );
2203 0 : jsonp_ulong( gui->http, "max_total_vote_cost", lslot->scheduler_stats->limits->max_vote_cost_per_block );
2204 0 : jsonp_ulong( gui->http, "max_account_write_cost", lslot->scheduler_stats->limits->max_write_cost_per_acct );
2205 0 : jsonp_ulong( gui->http, "max_total_bytes", lslot->scheduler_stats->limits->max_data_bytes_per_block );
2206 0 : jsonp_ulong( gui->http, "max_total_microblocks", lslot->max_microblocks );
2207 0 : jsonp_close_object( gui->http );
2208 :
2209 0 : jsonp_open_object( gui->http, "scheduler_stats" );
2210 0 : char block_hash_base58[ FD_BASE58_ENCODED_32_SZ ];
2211 0 : fd_base58_encode_32( lslot->block_hash.uc, NULL, block_hash_base58 );
2212 0 : jsonp_string( gui->http, "block_hash", block_hash_base58 );
2213 :
2214 0 : switch( lslot->scheduler_stats->end_slot_reason ) {
2215 0 : case FD_PACK_END_SLOT_REASON_TIME: {
2216 0 : jsonp_string( gui->http, "end_slot_reason", "timeout" );
2217 0 : break;
2218 0 : }
2219 0 : case FD_PACK_END_SLOT_REASON_MICROBLOCK: {
2220 0 : jsonp_string( gui->http, "end_slot_reason", "microblock_limit" );
2221 0 : break;
2222 0 : }
2223 0 : case FD_PACK_END_SLOT_REASON_LEADER_SWITCH: {
2224 0 : jsonp_string( gui->http, "end_slot_reason", "leader_switch" );
2225 0 : break;
2226 0 : }
2227 0 : default: FD_LOG_ERR(( "unreachable" ));
2228 0 : }
2229 0 : jsonp_open_array( gui->http, "slot_schedule_counts" );
2230 0 : for( ulong i = 0; i<FD_METRICS_COUNTER_PACK_TXN_SCHEDULED_CNT; i++ ) jsonp_ulong( gui->http, NULL, lslot->scheduler_stats->block_results[ i ] );
2231 0 : jsonp_close_array( gui->http );
2232 0 : jsonp_open_array( gui->http, "end_slot_schedule_counts" );
2233 0 : for( ulong i = 0; i<FD_METRICS_COUNTER_PACK_TXN_SCHEDULED_CNT; i++ ) jsonp_ulong( gui->http, NULL, lslot->scheduler_stats->end_block_results[ i ] );
2234 0 : jsonp_close_array( gui->http );
2235 :
2236 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 );
2237 0 : else jsonp_null( gui->http, "pending_smallest_cost" );
2238 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 );
2239 0 : else jsonp_null( gui->http, "pending_smallest_bytes" );
2240 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 );
2241 0 : else jsonp_null( gui->http, "pending_vote_smallest_cost" );
2242 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 );
2243 0 : else jsonp_null( gui->http, "pending_vote_smallest_bytes" );
2244 0 : jsonp_close_object( gui->http );
2245 :
2246 0 : } else {
2247 0 : jsonp_null( gui->http, "limits" );
2248 0 : jsonp_null( gui->http, "scheduler_stats" );
2249 0 : }
2250 :
2251 0 : int overwritten = lslot && (gui->pack_txn_idx - lslot->txs.start_offset)>FD_GUI_TXN_HISTORY_SZ;
2252 0 : int processed_all_microblocks = lslot && lslot->unbecame_leader &&
2253 0 : lslot->txs.start_offset!=ULONG_MAX &&
2254 0 : lslot->txs.end_offset!=ULONG_MAX &&
2255 0 : lslot->txs.microblocks_upper_bound!=UINT_MAX &&
2256 0 : lslot->txs.begin_microblocks==lslot->txs.end_microblocks &&
2257 0 : lslot->txs.begin_microblocks==lslot->txs.microblocks_upper_bound;
2258 :
2259 0 : if( FD_LIKELY( !overwritten && processed_all_microblocks ) ) {
2260 0 : ulong txn_cnt = lslot->txs.end_offset-lslot->txs.start_offset;
2261 :
2262 0 : jsonp_open_object( gui->http, "transactions" );
2263 0 : jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
2264 0 : jsonp_long_as_str( gui->http, "target_end_timestamp_nanos", lslot->leader_end_time );
2265 0 : jsonp_open_array( gui->http, "txn_mb_start_timestamps_nanos" );
2266 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 ]->microblock_start_ns_dt );
2267 0 : jsonp_close_array( gui->http );
2268 0 : jsonp_open_array( gui->http, "txn_mb_end_timestamps_nanos" );
2269 0 : for( ulong i=0UL; i<txn_cnt; i++) {
2270 0 : long const clamped_microblock_end_ns_dt = fd_long_max( (long)gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->microblock_end_ns_dt, (long)gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->microblock_start_ns_dt + 1L );
2271 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + clamped_microblock_end_ns_dt );
2272 0 : }
2273 0 : jsonp_close_array( gui->http );
2274 0 : jsonp_open_array( gui->http, "txn_compute_units_requested" );
2275 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 );
2276 0 : jsonp_close_array( gui->http );
2277 0 : jsonp_open_array( gui->http, "txn_compute_units_consumed" );
2278 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 );
2279 0 : jsonp_close_array( gui->http );
2280 0 : jsonp_open_array( gui->http, "txn_priority_fee" );
2281 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 );
2282 0 : jsonp_close_array( gui->http );
2283 0 : jsonp_open_array( gui->http, "txn_transaction_fee" );
2284 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 );
2285 0 : jsonp_close_array( gui->http );
2286 0 : jsonp_open_array( gui->http, "txn_error_code" );
2287 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 );
2288 0 : jsonp_close_array( gui->http );
2289 0 : jsonp_open_array( gui->http, "txn_from_bundle" );
2290 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 );
2291 0 : jsonp_close_array( gui->http );
2292 0 : jsonp_open_array( gui->http, "txn_is_simple_vote" );
2293 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 );
2294 0 : jsonp_close_array( gui->http );
2295 0 : jsonp_open_array( gui->http, "txn_bank_idx" );
2296 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 );
2297 0 : jsonp_close_array( gui->http );
2298 0 : jsonp_open_array( gui->http, "txn_check_start_timestamps_nanos" );
2299 0 : for( ulong i=0UL; i<txn_cnt; i++) {
2300 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
2301 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + (long)txn->microblock_start_ns_dt + (long)txn->txn_ns_dt.check_start );
2302 0 : }
2303 0 : jsonp_close_array( gui->http );
2304 0 : jsonp_open_array( gui->http, "txn_load_start_timestamps_nanos" );
2305 0 : for( ulong i=0UL; i<txn_cnt; i++) {
2306 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
2307 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + (long)txn->microblock_start_ns_dt + (long)txn->txn_ns_dt.load_start );
2308 0 : }
2309 0 : jsonp_close_array( gui->http );
2310 0 : jsonp_open_array( gui->http, "txn_execute_start_timestamps_nanos" );
2311 0 : for( ulong i=0UL; i<txn_cnt; i++) {
2312 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
2313 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + (long)txn->microblock_start_ns_dt + (long)txn->txn_ns_dt.exec_start );
2314 0 : }
2315 0 : jsonp_close_array( gui->http );
2316 0 : jsonp_open_array( gui->http, "txn_commit_start_timestamps_nanos" );
2317 0 : for( ulong i=0UL; i<txn_cnt; i++) {
2318 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
2319 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + (long)txn->microblock_start_ns_dt + (long)txn->txn_ns_dt.commit_start );
2320 0 : }
2321 0 : jsonp_close_array( gui->http );
2322 0 : jsonp_open_array( gui->http, "txn_commit_end_timestamps_nanos" );
2323 0 : for( ulong i=0UL; i<txn_cnt; i++) {
2324 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
2325 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + (long)txn->microblock_start_ns_dt + (long)txn->txn_ns_dt.commit_end );
2326 0 : }
2327 0 : jsonp_close_array( gui->http );
2328 0 : jsonp_open_array( gui->http, "txn_arrival_timestamps_nanos" );
2329 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 );
2330 0 : jsonp_close_array( gui->http );
2331 0 : jsonp_open_array( gui->http, "txn_tips" );
2332 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 );
2333 0 : jsonp_close_array( gui->http );
2334 0 : jsonp_open_array( gui->http, "txn_source_ipv4" );
2335 0 : for( ulong i=0UL; i<txn_cnt; i++) {
2336 0 : char addr[ 64 ];
2337 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 ) );
2338 0 : jsonp_string( gui->http, NULL, addr );
2339 0 : }
2340 0 : jsonp_close_array( gui->http );
2341 0 : jsonp_open_array( gui->http, "txn_source_tpu" );
2342 0 : for( ulong i=0UL; i<txn_cnt; i++) {
2343 0 : switch ( gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->source_tpu ) {
2344 0 : case FD_TXN_M_TPU_SOURCE_QUIC: {
2345 0 : jsonp_string( gui->http, NULL, "quic");
2346 0 : break;
2347 0 : }
2348 0 : case FD_TXN_M_TPU_SOURCE_UDP : {
2349 0 : jsonp_string( gui->http, NULL, "udp");
2350 0 : break;
2351 0 : }
2352 0 : case FD_TXN_M_TPU_SOURCE_GOSSIP: {
2353 0 : jsonp_string( gui->http, NULL, "gossip");
2354 0 : break;
2355 0 : }
2356 0 : case FD_TXN_M_TPU_SOURCE_BUNDLE: {
2357 0 : jsonp_string( gui->http, NULL, "bundle");
2358 0 : break;
2359 0 : }
2360 0 : case FD_TXN_M_TPU_SOURCE_TXSEND: {
2361 0 : jsonp_string( gui->http, NULL, "send");
2362 0 : break;
2363 0 : }
2364 0 : default: FD_LOG_ERR(("unknown tpu"));
2365 0 : }
2366 0 : }
2367 0 : jsonp_close_array( gui->http );
2368 0 : jsonp_open_array( gui->http, "txn_microblock_id" );
2369 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 );
2370 0 : jsonp_close_array( gui->http );
2371 0 : jsonp_open_array( gui->http, "txn_landed" );
2372 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 );
2373 0 : jsonp_close_array( gui->http );
2374 0 : jsonp_open_array( gui->http, "txn_signature" );
2375 0 : for( ulong i=0UL; i<txn_cnt; i++) {
2376 0 : FD_BASE58_ENCODE_64_BYTES( gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->signature, encoded_signature );
2377 0 : jsonp_string( gui->http, NULL, encoded_signature );
2378 0 : }
2379 0 : jsonp_close_array( gui->http );
2380 0 : jsonp_close_object( gui->http );
2381 0 : } else {
2382 0 : jsonp_null( gui->http, "transactions" );
2383 0 : }
2384 :
2385 0 : jsonp_close_object( gui->http );
2386 0 : jsonp_close_envelope( gui->http );
2387 0 : }
2388 :
2389 : void
2390 : fd_gui_printf_slot_request_detailed( fd_gui_t * gui,
2391 : ulong _slot,
2392 0 : ulong id ) {
2393 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
2394 :
2395 0 : char const * level;
2396 0 : switch( slot->level ) {
2397 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
2398 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
2399 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
2400 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
2401 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
2402 0 : default: level = "unknown"; break;
2403 0 : }
2404 :
2405 0 : fd_gui_slot_t * parent_slot = fd_gui_get_slot( gui, slot->parent_slot );
2406 0 : long duration_nanos = LONG_MAX;
2407 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
2408 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
2409 0 : }
2410 :
2411 0 : jsonp_open_envelope( gui->http, "slot", "query_detailed" );
2412 0 : jsonp_ulong( gui->http, "id", id );
2413 0 : jsonp_open_object( gui->http, "value" );
2414 0 : fd_gui_leader_slot_t * lslot = fd_gui_get_leader_slot( gui, _slot );
2415 :
2416 0 : jsonp_open_object( gui->http, "publish" );
2417 0 : jsonp_ulong( gui->http, "slot", _slot );
2418 0 : jsonp_bool( gui->http, "mine", slot->mine );
2419 0 : if( FD_UNLIKELY( slot->vote_slot!=ULONG_MAX ) ) jsonp_ulong( gui->http, "vote_slot", slot->vote_slot );
2420 0 : else jsonp_null( gui->http, "vote_slot" );
2421 0 : if( FD_UNLIKELY( slot->vote_latency!=UCHAR_MAX ) ) jsonp_ulong( gui->http, "vote_latency", slot->vote_latency );
2422 0 : else jsonp_null( gui->http, "vote_latency" );
2423 :
2424 0 : if( FD_UNLIKELY( lslot && lslot->leader_start_time!=LONG_MAX ) ) jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
2425 0 : else jsonp_null ( gui->http, "start_timestamp_nanos" );
2426 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 );
2427 0 : else jsonp_null ( gui->http, "target_end_timestamp_nanos" );
2428 :
2429 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
2430 0 : jsonp_string( gui->http, "level", level );
2431 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
2432 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
2433 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
2434 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
2435 0 : if( FD_UNLIKELY( slot->nonvote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
2436 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->nonvote_success );
2437 0 : if( FD_UNLIKELY( slot->nonvote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
2438 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed );
2439 0 : if( FD_UNLIKELY( slot->vote_success==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
2440 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_success );
2441 0 : if( FD_UNLIKELY( slot->vote_failed==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
2442 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->vote_failed );
2443 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
2444 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
2445 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
2446 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
2447 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
2448 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
2449 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
2450 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
2451 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
2452 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
2453 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
2454 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
2455 0 : jsonp_close_object( gui->http );
2456 :
2457 0 : if( FD_LIKELY( gui->summary.slot_completed!=ULONG_MAX && gui->summary.slot_completed>_slot ) ) {
2458 0 : fd_gui_printf_waterfall( gui, slot->waterfall_begin, slot->waterfall_end );
2459 :
2460 0 : fd_gui_leader_slot_t * lslot = fd_gui_get_leader_slot( gui, _slot );
2461 0 : if( FD_LIKELY( lslot && lslot->unbecame_leader ) ) {
2462 0 : jsonp_open_array( gui->http, "tile_timers" );
2463 0 : fd_gui_tile_timers_t const * prev_timer = lslot->tile_timers;
2464 0 : for( ulong i=1UL; i<lslot->tile_timers_sample_cnt; i++ ) {
2465 0 : fd_gui_tile_timers_t const * cur_timer = lslot->tile_timers + i * gui->tile_cnt;
2466 0 : fd_gui_printf_ts_tile_timers( gui, prev_timer, cur_timer );
2467 0 : prev_timer = cur_timer;
2468 0 : }
2469 0 : jsonp_close_array( gui->http );
2470 0 : } else {
2471 : /* Our tile timers were overwritten. */
2472 0 : jsonp_null( gui->http, "tile_timers" );
2473 0 : }
2474 :
2475 0 : if( FD_LIKELY( lslot && lslot->unbecame_leader ) ) {
2476 0 : jsonp_open_array( gui->http, "scheduler_counts" );
2477 : /* Unlike tile timers (which are counters), scheduler counts
2478 : are a gauge and we don't take a diff. */
2479 0 : for( ulong i=0UL; i<lslot->scheduler_counts_sample_cnt; i++ ) {
2480 0 : fd_gui_scheduler_counts_t const * cur = lslot->scheduler_counts[ i ];
2481 0 : jsonp_open_object( gui->http, NULL );
2482 0 : jsonp_long_as_str( gui->http, "timestamp_nanos", cur->sample_time_ns );
2483 0 : jsonp_ulong ( gui->http, "regular", cur->regular );
2484 0 : jsonp_ulong ( gui->http, "votes", cur->votes );
2485 0 : jsonp_ulong ( gui->http, "conflicting", cur->conflicting );
2486 0 : jsonp_ulong ( gui->http, "bundles", cur->bundles );
2487 0 : jsonp_close_object( gui->http );
2488 0 : }
2489 0 : jsonp_close_array( gui->http );
2490 0 : } else {
2491 : /* Our scheduler counts were overwritten. */
2492 0 : jsonp_null( gui->http, "scheduler_counts" );
2493 0 : }
2494 :
2495 0 : fd_gui_printf_tile_stats( gui, slot->tile_stats_begin, slot->tile_stats_end );
2496 0 : } else {
2497 0 : jsonp_null( gui->http, "waterfall" );
2498 0 : jsonp_null( gui->http, "tile_timers" );
2499 0 : jsonp_null( gui->http, "tile_primary_metric" );
2500 0 : }
2501 :
2502 0 : jsonp_close_object( gui->http );
2503 0 : jsonp_close_envelope( gui->http );
2504 0 : }
2505 :
2506 : void
2507 0 : fd_gui_printf_boot_progress( fd_gui_t * gui ) {
2508 0 : jsonp_open_envelope( gui->http, "summary", "boot_progress" );
2509 0 : jsonp_open_object( gui->http, "value" );
2510 0 : switch( gui->summary.boot_progress.phase ) {
2511 0 : case FD_GUI_BOOT_PROGRESS_TYPE_JOINING_GOSSIP: jsonp_string( gui->http, "phase", "joining_gossip" ); break;
2512 0 : case FD_GUI_BOOT_PROGRESS_TYPE_LOADING_FULL_SNAPSHOT: jsonp_string( gui->http, "phase", "loading_full_snapshot" ); break;
2513 0 : case FD_GUI_BOOT_PROGRESS_TYPE_LOADING_INCREMENTAL_SNAPSHOT: jsonp_string( gui->http, "phase", "loading_incremental_snapshot" ); break;
2514 0 : case FD_GUI_BOOT_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY: jsonp_string( gui->http, "phase", "waiting_for_supermajority" ); break;
2515 0 : case FD_GUI_BOOT_PROGRESS_TYPE_CATCHING_UP: jsonp_string( gui->http, "phase", "catching_up" ); break;
2516 0 : case FD_GUI_BOOT_PROGRESS_TYPE_RUNNING: jsonp_string( gui->http, "phase", "running" ); break;
2517 0 : default: FD_LOG_ERR(( "unknown phase %d", gui->summary.boot_progress.phase ));
2518 0 : }
2519 :
2520 0 : jsonp_double( gui->http, "joining_gossip_elapsed_seconds", (double)(gui->summary.boot_progress.joining_gossip_time_nanos - gui->summary.startup_time_nanos) / 1e9 );
2521 :
2522 0 : #define HANDLE_SNAPSHOT_STATE(snapshot_type, snapshot_type_upper) { \
2523 0 : ulong snapshot_idx = FD_GUI_BOOT_PROGRESS_##snapshot_type_upper##_SNAPSHOT_IDX; \
2524 0 : if( FD_LIKELY( gui->summary.boot_progress.phase>=FD_GUI_BOOT_PROGRESS_TYPE_LOADING_##snapshot_type_upper##_SNAPSHOT && gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].slot!=ULONG_MAX )) { \
2525 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 ); \
2526 0 : jsonp_ulong ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_reset_count", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].reset_cnt ); \
2527 0 : jsonp_ulong ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_slot", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].slot ); \
2528 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 ); \
2529 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 ); \
2530 0 : jsonp_string ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_read_path", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].read_path ); \
2531 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 ); \
2532 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 ); \
2533 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 ); \
2534 0 : jsonp_ulong ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_insert_accounts", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].insert_accounts_current ); \
2535 0 : jsonp_ulong_as_str( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_snapwr_in_bytes_decompressed", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].snapwr_in_bytes_decompressed ); \
2536 0 : jsonp_ulong_as_str( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_snapwr_out_bytes_decompressed", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].snapwr_out_bytes_decompressed ); \
2537 0 : jsonp_ulong ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_snapwr_accounts", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].snapwr_accounts_current ); \
2538 0 : } else { \
2539 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_elapsed_seconds" ); \
2540 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_reset_count" ); \
2541 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_slot" ); \
2542 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_total_bytes_compressed" ); \
2543 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_read_bytes_compressed" ); \
2544 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_read_path" ); \
2545 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_decompress_bytes_decompressed" ); \
2546 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_decompress_bytes_compressed" ); \
2547 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_insert_bytes_decompressed" ); \
2548 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_insert_accounts" ); \
2549 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_snapwr_in_bytes_decompressed" ); \
2550 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_snapwr_out_bytes_decompressed" ); \
2551 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_snapwr_accounts" ); \
2552 0 : } \
2553 0 : }
2554 :
2555 0 : HANDLE_SNAPSHOT_STATE(full, FULL)
2556 0 : HANDLE_SNAPSHOT_STATE(incremental, INCREMENTAL)
2557 0 : #undef HANDLE_SNAPSHOT_STATE
2558 :
2559 0 : if( FD_LIKELY( gui->summary.wfs_enabled ) ) {
2560 0 : jsonp_string ( gui->http, "wait_for_supermajority_bank_hash", gui->summary.wfs_bank_hash );
2561 0 : char shred_version_str[ 8 ];
2562 0 : FD_TEST( fd_cstr_printf_check( shred_version_str, sizeof(shred_version_str), NULL, "%hu", gui->summary.expected_shred_version ) );
2563 0 : jsonp_string ( gui->http, "wait_for_supermajority_shred_version", shred_version_str );
2564 0 : if( FD_LIKELY( gui->summary.boot_progress.phase>=FD_GUI_BOOT_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY ) ) {
2565 0 : jsonp_ulong ( gui->http, "wait_for_supermajority_attempt", gui->summary.boot_progress.wfs_attempt );
2566 0 : jsonp_ulong_as_str( gui->http, "wait_for_supermajority_total_stake", gui->summary.boot_progress.wfs_total_stake );
2567 0 : jsonp_ulong_as_str( gui->http, "wait_for_supermajority_connected_stake", gui->summary.boot_progress.wfs_connected_stake );
2568 0 : jsonp_ulong ( gui->http, "wait_for_supermajority_total_peers", gui->summary.boot_progress.wfs_total_peers );
2569 0 : jsonp_ulong ( gui->http, "wait_for_supermajority_connected_peers", gui->summary.boot_progress.wfs_connected_peers );
2570 0 : } else {
2571 0 : jsonp_null( gui->http, "wait_for_supermajority_attempt" );
2572 0 : jsonp_null( gui->http, "wait_for_supermajority_total_stake" );
2573 0 : jsonp_null( gui->http, "wait_for_supermajority_connected_stake" );
2574 0 : jsonp_null( gui->http, "wait_for_supermajority_total_peers" );
2575 0 : jsonp_null( gui->http, "wait_for_supermajority_connected_peers" );
2576 0 : }
2577 0 : } else {
2578 0 : jsonp_null( gui->http, "wait_for_supermajority_bank_hash" );
2579 0 : jsonp_null( gui->http, "wait_for_supermajority_shred_version" );
2580 0 : jsonp_null( gui->http, "wait_for_supermajority_attempt" );
2581 0 : jsonp_null( gui->http, "wait_for_supermajority_total_stake" );
2582 0 : jsonp_null( gui->http, "wait_for_supermajority_connected_stake" );
2583 0 : jsonp_null( gui->http, "wait_for_supermajority_total_peers" );
2584 0 : jsonp_null( gui->http, "wait_for_supermajority_connected_peers" );
2585 0 : }
2586 :
2587 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 );
2588 0 : else jsonp_null ( gui->http, "catching_up_elapsed_seconds" );
2589 :
2590 0 : if( FD_LIKELY( gui->summary.boot_progress.phase>=FD_GUI_BOOT_PROGRESS_TYPE_CATCHING_UP
2591 0 : && gui->summary.boot_progress.catching_up_first_replay_slot!=ULONG_MAX ) ) {
2592 0 : jsonp_ulong( gui->http, "catching_up_first_replay_slot", gui->summary.boot_progress.catching_up_first_replay_slot );
2593 0 : } else {
2594 0 : jsonp_null( gui->http, "catching_up_first_replay_slot" );
2595 0 : }
2596 :
2597 0 : jsonp_close_object( gui->http );
2598 0 : jsonp_close_envelope( gui->http );
2599 0 : }
2600 :
2601 : void
2602 : fd_gui_printf_peers_viewport_update( fd_gui_peers_ctx_t * peers,
2603 0 : ulong ws_conn_id ) {
2604 0 : jsonp_open_envelope( peers->http, "gossip", "view_update" );
2605 0 : jsonp_open_object( peers->http, "value" );
2606 0 : jsonp_open_array( peers->http, "changes" );
2607 0 : FD_TEST( peers->scratch.viewport_cnt<=FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ );
2608 :
2609 0 : ulong start_row = peers->client_viewports[ ws_conn_id ].start_row;
2610 0 : for( ulong i=0UL; i<peers->scratch.viewport_cnt; i++ ) {
2611 0 : ulong j = start_row + i;
2612 0 : fd_gui_peers_row_t const * cur = &peers->scratch.viewport[ i ];
2613 0 : fd_gui_peers_row_t const * ref = &peers->scratch.viewport_ref[ i ];
2614 :
2615 : /* This code should be kept in sync with updates to
2616 : fd_gui_peers_live_table */
2617 0 : if( FD_UNLIKELY( cur->stake!=ref->stake ) ) {
2618 0 : jsonp_open_object( peers->http, NULL );
2619 0 : jsonp_ulong ( peers->http, "row_index", j );
2620 0 : jsonp_string( peers->http, "column_name", "Stake" );
2621 :
2622 0 : if( FD_UNLIKELY( cur->stake==ULONG_MAX ) ) jsonp_long ( peers->http, "new_value", -1 );
2623 0 : else jsonp_ulong( peers->http, "new_value", cur->stake );
2624 0 : jsonp_close_object( peers->http );
2625 0 : }
2626 :
2627 0 : if( FD_UNLIKELY( strncmp( cur->name, ref->name, sizeof(ref->name) ) ) ) {
2628 0 : jsonp_open_object( peers->http, NULL );
2629 0 : jsonp_ulong ( peers->http, "row_index", j );
2630 0 : jsonp_string( peers->http, "column_name", "Name" );
2631 0 : jsonp_string( peers->http, "new_value", cur->name );
2632 0 : jsonp_close_object( peers->http );
2633 0 : }
2634 :
2635 0 : if( FD_UNLIKELY( cur->country_code_idx!=ref->country_code_idx ) ) {
2636 0 : jsonp_open_object( peers->http, NULL );
2637 0 : jsonp_ulong ( peers->http, "row_index", j );
2638 0 : jsonp_string( peers->http, "column_name", "Country" );
2639 0 : if( FD_LIKELY( cur->country_code_idx!=UCHAR_MAX ) ) {
2640 0 : jsonp_string( peers->http, "new_value", peers->dbip.country_code[ cur->country_code_idx ] );
2641 0 : } else {
2642 0 : jsonp_null( peers->http, "new_value" );
2643 0 : }
2644 0 : jsonp_close_object( peers->http );
2645 0 : }
2646 :
2647 0 : if( FD_UNLIKELY( memcmp( cur->pubkey.uc, ref->pubkey.uc, 32UL ) ) ) {
2648 0 : jsonp_open_object( peers->http, NULL );
2649 0 : jsonp_ulong ( peers->http, "row_index", j );
2650 0 : jsonp_string( peers->http, "column_name", "Pubkey" );
2651 :
2652 0 : char pubkey_base58[ FD_BASE58_ENCODED_32_SZ ];
2653 0 : fd_base58_encode_32( cur->pubkey.uc, NULL, pubkey_base58 );
2654 0 : jsonp_string( peers->http, "new_value", pubkey_base58 );
2655 0 : jsonp_close_object( peers->http );
2656 0 : }
2657 :
2658 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;
2659 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;
2660 0 : if( FD_UNLIKELY( ip4_after!=ip4_before ) ) {
2661 0 : jsonp_open_object( peers->http, NULL );
2662 0 : jsonp_ulong ( peers->http, "row_index", j );
2663 0 : jsonp_string( peers->http, "column_name", "IP Addr" );
2664 :
2665 0 : char peer_addr[ 16 ]; /* 255.255.255.255 + '\0' */
2666 0 : FD_TEST( fd_cstr_printf_check( peer_addr, sizeof(peer_addr), NULL, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( ip4_after ) ) );
2667 0 : jsonp_string( peers->http, "new_value", peer_addr );
2668 0 : jsonp_close_object( peers->http );
2669 0 : }
2670 :
2671 0 : long cur_egress_push_bps = cur->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema;
2672 0 : long ref_egress_push_bps = ref->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema;
2673 0 : long cur_ingress_push_bps = cur->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema;
2674 0 : long ref_ingress_push_bps = ref->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema;
2675 0 : long cur_egress_pull_response_bps = cur->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema;
2676 0 : long ref_egress_pull_response_bps = ref->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema;
2677 0 : long cur_ingress_pull_response_bps = cur->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema;
2678 0 : long ref_ingress_pull_response_bps = ref->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema;
2679 :
2680 0 : if( FD_UNLIKELY( ref->valid && cur_ingress_pull_response_bps!=ref_ingress_pull_response_bps ) ) {
2681 0 : jsonp_open_object( peers->http, NULL );
2682 0 : jsonp_ulong ( peers->http, "row_index", j );
2683 0 : jsonp_string( peers->http, "column_name", "Ingress Pull" );
2684 0 : jsonp_long ( peers->http, "new_value", cur_ingress_pull_response_bps );
2685 0 : jsonp_close_object( peers->http );
2686 0 : }
2687 :
2688 0 : if( FD_UNLIKELY( ref->valid && cur_ingress_push_bps!=ref_ingress_push_bps ) ) {
2689 0 : jsonp_open_object( peers->http, NULL );
2690 0 : jsonp_ulong ( peers->http, "row_index", j );
2691 0 : jsonp_string( peers->http, "column_name", "Ingress Push" );
2692 0 : jsonp_long ( peers->http, "new_value", cur_ingress_push_bps );
2693 0 : jsonp_close_object( peers->http );
2694 0 : }
2695 :
2696 0 : if( FD_UNLIKELY( ref->valid && cur_egress_pull_response_bps!=ref_egress_pull_response_bps ) ) {
2697 0 : jsonp_open_object( peers->http, NULL );
2698 0 : jsonp_ulong ( peers->http, "row_index", j );
2699 0 : jsonp_string( peers->http, "column_name", "Egress Pull" );
2700 0 : jsonp_long ( peers->http, "new_value", cur_egress_pull_response_bps );
2701 0 : jsonp_close_object( peers->http );
2702 0 : }
2703 :
2704 0 : if( FD_UNLIKELY( ref->valid && cur_egress_push_bps!=ref_egress_push_bps ) ) {
2705 0 : jsonp_open_object( peers->http, NULL );
2706 0 : jsonp_ulong ( peers->http, "row_index", j );
2707 0 : jsonp_string( peers->http, "column_name", "Egress Push" );
2708 0 : jsonp_long ( peers->http, "new_value", cur_egress_push_bps );
2709 0 : jsonp_close_object( peers->http );
2710 0 : }
2711 :
2712 0 : }
2713 0 : jsonp_close_array( peers->http );
2714 0 : jsonp_close_object( peers->http );
2715 0 : jsonp_close_envelope( peers->http );
2716 0 : }
2717 :
2718 : void
2719 : fd_gui_printf_peers_viewport_request( fd_gui_peers_ctx_t * peers,
2720 : char const * key,
2721 : ulong ws_conn_id,
2722 0 : ulong request_id ) {
2723 0 : jsonp_open_envelope( peers->http, "gossip", key );
2724 0 : jsonp_ulong( peers->http, "id", request_id );
2725 0 : jsonp_open_object( peers->http, "value" );
2726 0 : FD_TEST( peers->scratch.viewport_cnt<=FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ );
2727 0 : ulong start_row = peers->client_viewports[ ws_conn_id ].start_row;
2728 0 : for( ulong i=0UL; i<peers->scratch.viewport_cnt; i++ ) {
2729 0 : ulong j = start_row + i;
2730 0 : fd_gui_peers_row_t const * cur = &peers->scratch.viewport[ i ];
2731 :
2732 0 : char row_index_cstr[ 32 ];
2733 0 : FD_TEST( fd_cstr_printf_check( row_index_cstr, sizeof(row_index_cstr), NULL, "%lu", + j ) );
2734 0 : jsonp_open_object( peers->http, row_index_cstr );
2735 : /* This code should be kept in sync with updates to
2736 : fd_gui_peers_live_table */
2737 0 : if( FD_UNLIKELY( cur->stake==ULONG_MAX ) ) jsonp_long ( peers->http, "Stake", -1 );
2738 0 : else jsonp_ulong( peers->http, "Stake", cur->stake );
2739 :
2740 0 : char pubkey_base58[ FD_BASE58_ENCODED_32_SZ ];
2741 0 : fd_base58_encode_32( cur->pubkey.uc, NULL, pubkey_base58 );
2742 0 : jsonp_string( peers->http, "Pubkey", pubkey_base58 );
2743 0 : jsonp_string( peers->http, "Name", cur->name );
2744 0 : if( FD_LIKELY( cur->country_code_idx!=UCHAR_MAX ) ) {
2745 0 : jsonp_string( peers->http, "Country", peers->dbip.country_code[ cur->country_code_idx ] );
2746 0 : } else {
2747 0 : jsonp_null( peers->http, "Country" );
2748 0 : }
2749 :
2750 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;
2751 0 : char peer_addr[ 16 ]; /* 255.255.255.255 + '\0' */
2752 0 : FD_TEST( fd_cstr_printf_check( peer_addr, sizeof(peer_addr), NULL, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( ip4 ) ) );
2753 0 : jsonp_string( peers->http, "IP Addr", peer_addr );
2754 :
2755 0 : long cur_egress_push_bps = cur->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema;
2756 0 : long cur_ingress_push_bps = cur->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema;
2757 0 : long cur_egress_pull_response_bps = cur->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema;
2758 0 : long cur_ingress_pull_response_bps = cur->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema;
2759 :
2760 0 : jsonp_long ( peers->http, "Ingress Pull", cur_ingress_pull_response_bps );
2761 0 : jsonp_long ( peers->http, "Ingress Push", cur_ingress_push_bps );
2762 0 : jsonp_long ( peers->http, "Egress Pull", cur_egress_pull_response_bps );
2763 0 : jsonp_long ( peers->http, "Egress Push", cur_egress_push_bps );
2764 :
2765 0 : jsonp_close_object( peers->http );
2766 0 : }
2767 :
2768 0 : jsonp_close_object( peers->http );
2769 0 : jsonp_close_envelope( peers->http );
2770 0 : }
2771 :
2772 : void
2773 0 : fd_gui_printf_peers_view_resize( fd_gui_peers_ctx_t * peers, ulong sz ) {
2774 0 : jsonp_open_envelope( peers->http, "gossip", "peers_size_update" );
2775 0 : jsonp_ulong( peers->http, "value", sz );
2776 0 : jsonp_close_envelope( peers->http );
2777 0 : }
2778 :
2779 : void
2780 0 : fd_gui_peers_printf_gossip_stats( fd_gui_peers_ctx_t * peers ) {
2781 0 : fd_gui_peers_gossip_stats_t * cur = peers->gossip_stats;
2782 :
2783 0 : jsonp_open_envelope( peers->http, "gossip", "network_stats" );
2784 0 : jsonp_open_object( peers->http, "value" );
2785 :
2786 0 : jsonp_open_object( peers->http, "health" );
2787 0 : jsonp_ulong ( peers->http, "num_push_messages_rx_success", cur->network_health_push_msg_rx_success );
2788 0 : jsonp_ulong ( peers->http, "num_push_messages_rx_failure", cur->network_health_push_msg_rx_failure );
2789 0 : jsonp_ulong ( peers->http, "num_push_entries_rx_success", cur->network_health_push_crds_rx_success );
2790 0 : jsonp_ulong ( peers->http, "num_push_entries_rx_failure", cur->network_health_push_crds_rx_failure );
2791 0 : jsonp_ulong ( peers->http, "num_push_entries_rx_duplicate", cur->network_health_push_crds_rx_duplicate );
2792 0 : jsonp_ulong ( peers->http, "num_pull_response_messages_rx_success", cur->network_health_pull_response_msg_rx_success );
2793 0 : jsonp_ulong ( peers->http, "num_pull_response_messages_rx_failure", cur->network_health_pull_response_msg_rx_failure );
2794 0 : jsonp_ulong ( peers->http, "num_pull_response_entries_rx_success", cur->network_health_pull_response_crds_rx_success );
2795 0 : jsonp_ulong ( peers->http, "num_pull_response_entries_rx_failure", cur->network_health_pull_response_crds_rx_failure );
2796 0 : jsonp_ulong ( peers->http, "num_pull_response_entries_rx_duplicate", cur->network_health_pull_response_crds_rx_duplicate );
2797 0 : jsonp_ulong_as_str( peers->http, "total_stake", cur->network_health_total_stake );
2798 0 : jsonp_ulong ( peers->http, "total_peers", cur->network_health_total_peers );
2799 0 : jsonp_ulong_as_str( peers->http, "connected_stake", cur->network_health_connected_stake );
2800 0 : jsonp_ulong ( peers->http, "connected_staked_peers", cur->network_health_connected_staked_peers );
2801 0 : jsonp_ulong ( peers->http, "connected_unstaked_peers", cur->network_health_connected_unstaked_peers );
2802 0 : jsonp_close_object( peers->http );
2803 :
2804 0 : jsonp_open_object( peers->http, "ingress" );
2805 :
2806 0 : jsonp_open_array( peers->http, "peer_names" );
2807 0 : for( ulong i=0UL; i<cur->network_ingress_peer_sz; i++ ) jsonp_string( peers->http, NULL, cur->network_ingress_peer_names[ i ] );
2808 0 : jsonp_close_array( peers->http );
2809 :
2810 0 : jsonp_open_array( peers->http, "peer_identities" );
2811 0 : for( ulong i=0UL; i<cur->network_ingress_peer_sz; i++ ) {
2812 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
2813 0 : fd_base58_encode_32( cur->network_ingress_peer_identities[ i ].uc, NULL, identity_base58 );
2814 0 : jsonp_string( peers->http, NULL, identity_base58 );
2815 0 : }
2816 0 : jsonp_close_array( peers->http );
2817 :
2818 0 : jsonp_open_array( peers->http, "peer_throughput" );
2819 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 ] );
2820 0 : jsonp_close_array( peers->http );
2821 0 : jsonp_long( peers->http, "total_throughput", cur->network_ingress_total_bytes_per_sec );
2822 0 : jsonp_close_object( peers->http );
2823 :
2824 0 : jsonp_open_object( peers->http, "egress" );
2825 0 : jsonp_open_array( peers->http, "peer_names" );
2826 0 : for( ulong i=0UL; i<cur->network_egress_peer_sz; i++ ) jsonp_string( peers->http, NULL, cur->network_egress_peer_names[ i ] );
2827 0 : jsonp_close_array( peers->http );
2828 :
2829 0 : jsonp_open_array( peers->http, "peer_identities" );
2830 0 : for( ulong i=0UL; i<cur->network_egress_peer_sz; i++ ) {
2831 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
2832 0 : fd_base58_encode_32( cur->network_egress_peer_identities[ i ].uc, NULL, identity_base58 );
2833 0 : jsonp_string( peers->http, NULL, identity_base58 );
2834 0 : }
2835 0 : jsonp_close_array( peers->http );
2836 :
2837 0 : jsonp_open_array( peers->http, "peer_throughput" );
2838 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 ] );
2839 0 : jsonp_close_array( peers->http );
2840 0 : jsonp_long( peers->http, "total_throughput", cur->network_egress_total_bytes_per_sec );
2841 0 : jsonp_close_object( peers->http );
2842 :
2843 0 : jsonp_open_object( peers->http, "storage" );
2844 : /* since these are gauges, we don't take a diff */
2845 0 : jsonp_ulong( peers->http, "capacity", cur->storage_capacity );
2846 0 : jsonp_ulong( peers->http, "expired_count", cur->storage_expired_cnt );
2847 0 : jsonp_ulong( peers->http, "evicted_count", cur->storage_evicted_cnt );
2848 0 : jsonp_open_array( peers->http, "count" );
2849 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_CRDS_VALUE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->storage_active_cnt[ i ] );
2850 0 : jsonp_close_array( peers->http );
2851 0 : jsonp_open_array( peers->http, "count_tx" );
2852 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_CRDS_VALUE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->storage_cnt_tx[ i ] );
2853 0 : jsonp_close_array( peers->http );
2854 0 : jsonp_open_array( peers->http, "bytes_tx" );
2855 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_CRDS_VALUE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->storage_bytes_tx[ i ] );
2856 0 : jsonp_close_array( peers->http );
2857 0 : jsonp_close_object( peers->http );
2858 0 : jsonp_open_object( peers->http, "messages" );
2859 0 : jsonp_open_array( peers->http, "num_bytes_rx" );
2860 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->messages_bytes_rx[ i ] );
2861 0 : jsonp_close_array( peers->http );
2862 0 : jsonp_open_array( peers->http, "num_bytes_tx" );
2863 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->messages_bytes_tx[ i ] );
2864 0 : jsonp_close_array( peers->http );
2865 0 : jsonp_open_array( peers->http, "num_messages_rx" );
2866 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->messages_count_rx[ i ] );
2867 0 : jsonp_close_array( peers->http );
2868 0 : jsonp_open_array( peers->http, "num_messages_tx" );
2869 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->messages_count_tx[ i ] );
2870 0 : jsonp_close_array( peers->http );
2871 0 : jsonp_close_object( peers->http );
2872 0 : jsonp_close_object( peers->http );
2873 0 : jsonp_close_envelope( peers->http );
2874 0 : }
2875 :
2876 : void
2877 0 : fd_gui_printf_shreds_staged( fd_gui_t * gui, ulong start_offset, ulong end_offset ) {
2878 0 : ulong min_slot = ULONG_MAX;
2879 0 : long min_ts = LONG_MAX;
2880 :
2881 0 : for( ulong i=start_offset; i<end_offset; i++ ) {
2882 0 : min_slot = fd_ulong_min( min_slot, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].slot );
2883 0 : min_ts = fd_long_min ( min_ts, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].timestamp );
2884 0 : }
2885 :
2886 0 : jsonp_ulong ( gui->http, "reference_slot", min_slot );
2887 0 : jsonp_long_as_str( gui->http, "reference_ts", min_ts );
2888 :
2889 0 : jsonp_open_array( gui->http, "slot_delta" );
2890 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 );
2891 0 : jsonp_close_array( gui->http );
2892 0 : jsonp_open_array( gui->http, "shred_idx" );
2893 0 : for( ulong i=start_offset; i<end_offset; i++ ) {
2894 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 );
2895 0 : else jsonp_null ( gui->http, NULL );
2896 0 : }
2897 0 : jsonp_close_array( gui->http );
2898 0 : jsonp_open_array( gui->http, "event" );
2899 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 );
2900 0 : jsonp_close_array( gui->http );
2901 0 : jsonp_open_array( gui->http, "event_ts_delta" );
2902 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 );
2903 0 : jsonp_close_array( gui->http );
2904 0 : }
2905 :
2906 : void
2907 0 : fd_gui_printf_shreds_history( fd_gui_t * gui, ulong _slot ) {
2908 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
2909 0 : FD_TEST( slot );
2910 0 : ulong end_offset = slot->shreds.end_offset;
2911 0 : ulong start_offset = slot->shreds.start_offset;
2912 0 : FD_TEST( slot->shreds.end_offset + FD_GUI_SHREDS_HISTORY_SZ > gui->shreds.history_tail );
2913 :
2914 0 : long min_ts = LONG_MAX;
2915 0 : for( ulong i=start_offset; i<end_offset; i++ ) {
2916 0 : min_ts = fd_long_min ( min_ts, gui->shreds.history[ i % FD_GUI_SHREDS_HISTORY_SZ ].timestamp );
2917 0 : }
2918 :
2919 0 : jsonp_ulong ( gui->http, "reference_slot", _slot );
2920 0 : jsonp_long_as_str( gui->http, "reference_ts", min_ts );
2921 :
2922 0 : jsonp_open_array( gui->http, "slot_delta" );
2923 0 : for( ulong i=start_offset; i<end_offset; i++ ) jsonp_ulong( gui->http, NULL, 0UL );
2924 0 : jsonp_close_array( gui->http );
2925 0 : jsonp_open_array( gui->http, "shred_idx" );
2926 0 : for( ulong i=start_offset; i<end_offset; i++ ) {
2927 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 );
2928 0 : else jsonp_null ( gui->http, NULL );
2929 0 : }
2930 0 : jsonp_close_array( gui->http );
2931 0 : jsonp_open_array( gui->http, "event" );
2932 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 );
2933 0 : jsonp_close_array( gui->http );
2934 0 : jsonp_open_array( gui->http, "event_ts_delta" );
2935 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 );
2936 0 : jsonp_close_array( gui->http );
2937 0 : }
2938 :
2939 : void
2940 0 : fd_gui_printf_shred_updates( fd_gui_t * gui ) {
2941 0 : jsonp_open_envelope( gui->http, "slot", "live_shreds" );
2942 0 : jsonp_open_object( gui->http, "value" );
2943 0 : fd_gui_printf_shreds_staged( gui, gui->shreds.staged_next_broadcast, gui->shreds.staged_tail );
2944 0 : jsonp_close_object( gui->http );
2945 0 : jsonp_close_envelope( gui->http );
2946 0 : }
2947 :
2948 : void
2949 0 : fd_gui_printf_shred_rebroadcast( fd_gui_t * gui, long after ) {
2950 0 : FD_TEST( gui->shreds.staged_next_broadcast!=ULONG_MAX );
2951 :
2952 0 : ulong _start_offset = gui->shreds.staged_next_broadcast;
2953 0 : for( ulong i=gui->shreds.staged_head; i<gui->shreds.staged_next_broadcast; i++ ) {
2954 0 : if( FD_LIKELY( gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].timestamp<after ) ) continue;
2955 0 : _start_offset = i;
2956 0 : break;
2957 0 : }
2958 :
2959 0 : jsonp_open_envelope( gui->http, "slot", "live_shreds" );
2960 0 : jsonp_open_object( gui->http, "value" );
2961 0 : fd_gui_printf_shreds_staged( gui, _start_offset, gui->shreds.staged_next_broadcast );
2962 0 : jsonp_close_object( gui->http );
2963 0 : jsonp_close_envelope( gui->http );
2964 0 : }
2965 :
2966 : void
2967 : fd_gui_printf_slot_query_shreds( fd_gui_t * gui,
2968 : ulong _slot,
2969 0 : ulong id ) {
2970 0 : jsonp_open_envelope( gui->http, "slot", "query_shreds" );
2971 0 : jsonp_ulong( gui->http, "id", id );
2972 0 : jsonp_open_object( gui->http, "value" );
2973 0 : fd_gui_printf_shreds_history( gui, _slot );
2974 0 : jsonp_close_object( gui->http );
2975 0 : jsonp_close_envelope( gui->http );
2976 0 : }
2977 :
2978 : void
2979 : fd_gui_peers_printf_wfs_add( fd_gui_peers_ctx_t * peers,
2980 : ulong const * idxs,
2981 0 : ulong cnt ) {
2982 0 : jsonp_open_envelope( peers->http, "wait_for_supermajority", "peer_add" );
2983 0 : jsonp_open_array( peers->http, "value" );
2984 0 : for( ulong i=0UL; i<cnt; i++ ) {
2985 0 : fd_gui_wfs_peer_t * wp = &peers->wfs_peers[ idxs[ i ] ];
2986 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
2987 0 : fd_base58_encode_32( wp->identity_key.uc, NULL, identity_base58 );
2988 0 : jsonp_string( peers->http, NULL, identity_base58 );
2989 0 : }
2990 0 : jsonp_close_array( peers->http );
2991 0 : jsonp_close_envelope( peers->http );
2992 0 : }
2993 :
2994 : void
2995 : fd_gui_peers_printf_wfs_remove( fd_gui_peers_ctx_t * peers,
2996 : ulong const * idxs,
2997 0 : ulong cnt ) {
2998 0 : jsonp_open_envelope( peers->http, "wait_for_supermajority", "peer_remove" );
2999 0 : jsonp_open_array( peers->http, "value" );
3000 0 : for( ulong i=0UL; i<cnt; i++ ) {
3001 0 : fd_gui_wfs_peer_t * wp = &peers->wfs_peers[ idxs[ i ] ];
3002 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
3003 0 : fd_base58_encode_32( wp->identity_key.uc, NULL, identity_base58 );
3004 0 : jsonp_string( peers->http, NULL, identity_base58 );
3005 0 : }
3006 0 : jsonp_close_array( peers->http );
3007 0 : jsonp_close_envelope( peers->http );
3008 0 : }
3009 :
3010 : void
3011 0 : fd_gui_peers_printf_wfs_stakes( fd_gui_peers_ctx_t * peers ) {
3012 0 : jsonp_open_envelope( peers->http, "wait_for_supermajority", "stakes" );
3013 0 : jsonp_open_object( peers->http, "value" );
3014 :
3015 0 : jsonp_open_array( peers->http, "staked_pubkeys" );
3016 0 : for( ulong i=0UL; i<peers->wfs_peers_cnt; i++ ) {
3017 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
3018 0 : fd_base58_encode_32( peers->wfs_peers[ i ].identity_key.uc, NULL, identity_base58 );
3019 0 : jsonp_string( peers->http, NULL, identity_base58 );
3020 0 : }
3021 0 : jsonp_close_array( peers->http );
3022 :
3023 0 : jsonp_open_array( peers->http, "staked_lamports" );
3024 0 : for( ulong i=0UL; i<peers->wfs_peers_cnt; i++ ) {
3025 0 : jsonp_ulong_as_str( peers->http, NULL, peers->wfs_peers[ i ].stake );
3026 0 : }
3027 0 : jsonp_close_array( peers->http );
3028 :
3029 0 : jsonp_open_array( peers->http, "infos" );
3030 0 : for( ulong i=0UL; i<peers->wfs_peers_cnt; i++ ) {
3031 0 : fd_gui_config_parse_info_t * info =
3032 0 : fd_gui_peers_node_info_map_ele_query(
3033 0 : peers->node_info_map, &peers->wfs_peers[ i ].identity_key, NULL, peers->node_info_pool );
3034 0 : if( info ) {
3035 0 : jsonp_open_object( peers->http, NULL );
3036 0 : jsonp_string( peers->http, "name", info->name );
3037 0 : jsonp_string( peers->http, "details", info->details );
3038 0 : jsonp_string( peers->http, "website", info->website );
3039 0 : jsonp_string( peers->http, "icon_url", info->icon_uri );
3040 0 : jsonp_string( peers->http, "keybase_username", info->keybase_username );
3041 0 : jsonp_close_object( peers->http );
3042 0 : } else {
3043 0 : jsonp_null( peers->http, NULL );
3044 0 : }
3045 0 : }
3046 0 : jsonp_close_array( peers->http );
3047 :
3048 0 : jsonp_close_object( peers->http );
3049 0 : jsonp_close_envelope( peers->http );
3050 0 : }
|