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