Line data Source code
1 : #include "fd_gui_printf.h"
2 :
3 : #include "../../waltz/http/fd_http_server_private.h"
4 : #include "../../ballet/utf8/fd_utf8.h"
5 : #include "../../disco/fd_txn_m.h"
6 :
7 : #ifdef __has_include
8 : #if __has_include("../../app/fdctl/version.h")
9 : #include "../../app/fdctl/version.h"
10 : #endif
11 : #endif
12 :
13 : #ifndef FDCTL_COMMIT_REF_CSTR
14 : #define FDCTL_COMMIT_REF_CSTR "0000000000000000000000000000000000000000"
15 : #endif
16 :
17 : static void
18 0 : jsonp_strip_trailing_comma( fd_http_server_t * http ) {
19 0 : if( FD_LIKELY( !http->stage_err &&
20 0 : http->stage_len>=1UL &&
21 0 : http->oring[ (http->stage_off%http->oring_sz)+http->stage_len-1UL ]==(uchar)',' ) ) {
22 0 : http->stage_len--;
23 0 : }
24 0 : }
25 :
26 : static void
27 : jsonp_open_object( fd_http_server_t * http,
28 0 : char const * key ) {
29 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":{", key );
30 0 : else fd_http_server_printf( http, "{" );
31 0 : }
32 :
33 : static void
34 0 : jsonp_close_object( fd_http_server_t * http ) {
35 0 : jsonp_strip_trailing_comma( http );
36 0 : fd_http_server_printf( http, "}," );
37 0 : }
38 :
39 : static void
40 : jsonp_open_array( fd_http_server_t * http,
41 0 : char const * key ) {
42 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":[", key );
43 0 : else fd_http_server_printf( http, "[" );
44 0 : }
45 :
46 : static void
47 0 : jsonp_close_array( fd_http_server_t * http ) {
48 0 : jsonp_strip_trailing_comma( http );
49 0 : fd_http_server_printf( http, "]," );
50 0 : }
51 :
52 : static void
53 : jsonp_ulong( fd_http_server_t * http,
54 : char const * key,
55 0 : ulong value ) {
56 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%lu,", key, value );
57 0 : else fd_http_server_printf( http, "%lu,", value );
58 0 : }
59 :
60 : static void
61 : jsonp_long( fd_http_server_t * http,
62 : char const * key,
63 0 : long value ) {
64 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%ld,", key, value );
65 0 : else fd_http_server_printf( http, "%ld,", value );
66 0 : }
67 :
68 : static void
69 : jsonp_double( fd_http_server_t * http,
70 : char const * key,
71 0 : double value ) {
72 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%.2f,", key, value );
73 0 : else fd_http_server_printf( http, "%.2f,", value );
74 0 : }
75 :
76 : static void
77 : jsonp_ulong_as_str( fd_http_server_t * http,
78 : char const * key,
79 0 : ulong value ) {
80 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":\"%lu\",", key, value );
81 0 : else fd_http_server_printf( http, "\"%lu\",", value );
82 0 : }
83 :
84 : static void
85 : jsonp_long_as_str( fd_http_server_t * http,
86 : char const * key,
87 0 : long value ) {
88 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":\"%ld\",", key, value );
89 0 : else fd_http_server_printf( http, "\"%ld\",", value );
90 0 : }
91 :
92 : static void
93 : jsonp_sanitize_str( fd_http_server_t * http,
94 0 : ulong start_len ) {
95 : /* escape quotemark, reverse solidus, and control chars U+0000 through U+001F
96 : just replace with a space */
97 0 : uchar * data = http->oring;
98 0 : for( ulong i=start_len; i<http->stage_len; i++ ) {
99 0 : if( FD_UNLIKELY( data[ (http->stage_off%http->oring_sz)+i ] < 0x20 ||
100 0 : data[ (http->stage_off%http->oring_sz)+i ] == '"' ||
101 0 : data[ (http->stage_off%http->oring_sz)+i ] == '\\' ) ) {
102 0 : data[ (http->stage_off%http->oring_sz)+i ] = ' ';
103 0 : }
104 0 : }
105 0 : }
106 :
107 : static void
108 : jsonp_string( fd_http_server_t * http,
109 : char const * key,
110 0 : char const * value ) {
111 0 : char * val = (void *)value;
112 0 : if( FD_LIKELY( value ) ) {
113 0 : if( FD_UNLIKELY( !fd_utf8_verify( value, strlen( value ) ) )) {
114 0 : val = NULL;
115 0 : }
116 0 : }
117 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":", key );
118 0 : if( FD_LIKELY( val ) ) {
119 0 : fd_http_server_printf( http, "\"" );
120 0 : ulong start_len = http->stage_len;
121 0 : fd_http_server_printf( http, "%s", val );
122 0 : jsonp_sanitize_str( http, start_len );
123 0 : fd_http_server_printf( http, "\"," );
124 0 : } else {
125 0 : fd_http_server_printf( http, "null," );
126 0 : }
127 0 : }
128 :
129 : static void
130 : jsonp_bool( fd_http_server_t * http,
131 : char const * key,
132 0 : int value ) {
133 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%s,", key, value ? "true" : "false" );
134 0 : else fd_http_server_printf( http, "%s,", value ? "true" : "false" );
135 0 : }
136 :
137 : static void
138 : jsonp_null( fd_http_server_t * http,
139 0 : char const * key ) {
140 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\": null,", key );
141 0 : else fd_http_server_printf( http, "null," );
142 0 : }
143 :
144 : static void
145 : jsonp_open_envelope( fd_http_server_t * http,
146 : char const * topic,
147 0 : char const * key ) {
148 0 : jsonp_open_object( http, NULL );
149 0 : jsonp_string( http, "topic", topic );
150 0 : jsonp_string( http, "key", key );
151 0 : }
152 :
153 : static void
154 0 : jsonp_close_envelope( fd_http_server_t * http ) {
155 0 : jsonp_close_object( http );
156 0 : jsonp_strip_trailing_comma( http );
157 0 : }
158 :
159 : void
160 : fd_gui_printf_open_query_response_envelope( fd_http_server_t * http,
161 : char const * topic,
162 : char const * key,
163 0 : ulong id ) {
164 0 : jsonp_open_object( http, NULL );
165 0 : jsonp_string( http, "topic", topic );
166 0 : jsonp_string( http, "key", key );
167 0 : jsonp_ulong( http, "id", id );
168 0 : }
169 :
170 : void
171 0 : fd_gui_printf_close_query_response_envelope( fd_http_server_t * http ) {
172 0 : jsonp_close_object( http );
173 0 : jsonp_strip_trailing_comma( http );
174 0 : }
175 :
176 : void
177 : fd_gui_printf_null_query_response( fd_http_server_t * http,
178 : char const * topic,
179 : char const * key,
180 0 : ulong id ) {
181 0 : fd_gui_printf_open_query_response_envelope( http, topic, key, id );
182 0 : jsonp_null( http, "value" );
183 0 : fd_gui_printf_close_query_response_envelope( http );
184 0 : }
185 :
186 : void
187 0 : fd_gui_printf_version( fd_gui_t * gui ) {
188 0 : jsonp_open_envelope( gui->http, "summary", "version" );
189 0 : jsonp_string( gui->http, "value", gui->summary.version );
190 0 : jsonp_close_envelope( gui->http );
191 0 : }
192 :
193 : void
194 0 : fd_gui_printf_cluster( fd_gui_t * gui ) {
195 0 : jsonp_open_envelope( gui->http, "summary", "cluster" );
196 0 : jsonp_string( gui->http, "value", gui->summary.cluster );
197 0 : jsonp_close_envelope( gui->http );
198 0 : }
199 :
200 : void
201 0 : fd_gui_printf_commit_hash( fd_gui_t * gui ) {
202 0 : jsonp_open_envelope( gui->http, "summary", "commit_hash" );
203 0 : jsonp_string( gui->http, "value", FDCTL_COMMIT_REF_CSTR );
204 0 : jsonp_close_envelope( gui->http );
205 0 : }
206 :
207 : void
208 0 : fd_gui_printf_identity_key( fd_gui_t * gui ) {
209 0 : jsonp_open_envelope( gui->http, "summary", "identity_key" );
210 0 : jsonp_string( gui->http, "value", gui->summary.identity_key_base58 );
211 0 : jsonp_close_envelope( gui->http );
212 0 : }
213 :
214 : void
215 0 : fd_gui_printf_vote_key( fd_gui_t * gui ) {
216 0 : jsonp_open_envelope( gui->http, "summary", "vote_key" );
217 0 : if( FD_LIKELY( gui->summary.has_vote_key ) ) jsonp_string( gui->http, "value", gui->summary.vote_key_base58 );
218 0 : else jsonp_null( gui->http, "value" );
219 0 : jsonp_close_envelope( gui->http );
220 0 : }
221 :
222 : void
223 0 : fd_gui_printf_startup_time_nanos( fd_gui_t * gui ) {
224 0 : jsonp_open_envelope( gui->http, "summary", "startup_time_nanos" );
225 0 : jsonp_long_as_str( gui->http, "value", gui->summary.startup_time_nanos );
226 0 : jsonp_close_envelope( gui->http );
227 0 : }
228 :
229 : void
230 0 : fd_gui_printf_vote_distance( fd_gui_t * gui ) {
231 0 : jsonp_open_envelope( gui->http, "summary", "vote_distance" );
232 0 : jsonp_ulong( gui->http, "value", gui->summary.vote_distance );
233 0 : jsonp_close_envelope( gui->http );
234 0 : }
235 :
236 : void
237 0 : fd_gui_printf_repair_slot( fd_gui_t * gui ) {
238 0 : jsonp_open_envelope( gui->http, "summary", "repair_slot" );
239 0 : if( FD_LIKELY( gui->summary.slot_repair!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_repair );
240 0 : else jsonp_null ( gui->http, "value" );
241 0 : jsonp_close_envelope( gui->http );
242 0 : }
243 :
244 : void
245 0 : fd_gui_printf_turbine_slot( fd_gui_t * gui ) {
246 0 : jsonp_open_envelope( gui->http, "summary", "turbine_slot" );
247 0 : if( FD_LIKELY( gui->summary.slot_turbine!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_turbine );
248 0 : else jsonp_null ( gui->http, "value" );
249 0 : jsonp_close_envelope( gui->http );
250 0 : }
251 :
252 : void
253 0 : fd_gui_printf_slot_caught_up( fd_gui_t * gui ) {
254 0 : jsonp_open_envelope( gui->http, "summary", "slot_caught_up" );
255 0 : if( FD_LIKELY( gui->summary.slot_caught_up!=ULONG_MAX ) ) jsonp_ulong( gui->http, "value", gui->summary.slot_caught_up );
256 0 : else jsonp_null ( gui->http, "value" );
257 0 : jsonp_close_envelope( gui->http );
258 0 : }
259 :
260 : void
261 0 : fd_gui_printf_catch_up_history( fd_gui_t * gui ) {
262 0 : jsonp_open_envelope( gui->http, "summary", "catch_up_history" );
263 0 : jsonp_open_object( gui->http, "value" );
264 0 : jsonp_open_array( gui->http, "turbine" );
265 0 : for( ulong i=0UL; i<gui->summary.catch_up_turbine_sz; i+=2 ) {
266 0 : for( ulong j=gui->summary.catch_up_turbine[ i ]; j<=gui->summary.catch_up_turbine[ i+1UL ]; j++ ) {
267 0 : jsonp_ulong( gui->http, NULL, j );
268 0 : }
269 0 : }
270 0 : jsonp_close_array( gui->http );
271 0 : jsonp_open_array( gui->http, "repair" );
272 0 : for( ulong i=0UL; i<gui->summary.catch_up_repair_sz; i+=2 ) {
273 0 : for( ulong j=gui->summary.catch_up_repair[ i ]; j<=gui->summary.catch_up_repair[ i+1UL ]; j++ ) {
274 0 : jsonp_ulong( gui->http, NULL, j );
275 0 : }
276 0 : }
277 0 : jsonp_close_array( gui->http );
278 0 : jsonp_close_object( gui->http );
279 0 : jsonp_close_envelope( gui->http );
280 0 : }
281 :
282 : void
283 0 : fd_gui_printf_vote_state( fd_gui_t * gui ) {
284 0 : jsonp_open_envelope( gui->http, "summary", "vote_state" );
285 0 : switch( gui->summary.vote_state ) {
286 0 : case FD_GUI_VOTE_STATE_NON_VOTING:
287 0 : jsonp_string( gui->http, "value", "non-voting" );
288 0 : break;
289 0 : case FD_GUI_VOTE_STATE_VOTING:
290 0 : jsonp_string( gui->http, "value", "voting" );
291 0 : break;
292 0 : case FD_GUI_VOTE_STATE_DELINQUENT:
293 0 : jsonp_string( gui->http, "value", "delinquent" );
294 0 : break;
295 0 : default:
296 0 : FD_LOG_ERR(( "unknown vote state %d", gui->summary.vote_state ));
297 0 : }
298 0 : jsonp_close_envelope( gui->http );
299 0 : }
300 :
301 : void
302 0 : fd_gui_printf_skipped_history( fd_gui_t * gui ) {
303 0 : jsonp_open_envelope( gui->http, "slot", "skipped_history" );
304 0 : jsonp_open_array( gui->http, "value" );
305 0 : for( ulong i=0UL; i<fd_ulong_min( gui->summary.slot_completed+1, FD_GUI_SLOTS_CNT ); i++ ) {
306 0 : if( FD_LIKELY( gui->summary.slot_completed==ULONG_MAX ) ) break;
307 0 : ulong _slot = gui->summary.slot_completed-i;
308 0 : fd_gui_slot_t * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
309 :
310 0 : if( FD_UNLIKELY( slot->slot!=_slot ) ) break;
311 0 : if( FD_UNLIKELY( slot->mine && slot->skipped ) ) jsonp_ulong( gui->http, NULL, slot->slot );
312 0 : }
313 0 : jsonp_close_array( gui->http );
314 0 : jsonp_close_envelope( gui->http );
315 0 : }
316 :
317 : void
318 0 : fd_gui_printf_skipped_history_cluster( fd_gui_t * gui ) {
319 0 : jsonp_open_envelope( gui->http, "slot", "skipped_history_cluster" );
320 0 : jsonp_open_array( gui->http, "value" );
321 0 : for( ulong i=0UL; i<fd_ulong_min( gui->summary.slot_completed+1UL, FD_GUI_SLOTS_CNT ); i++ ) {
322 0 : if( FD_LIKELY( gui->summary.slot_completed==ULONG_MAX ) ) break;
323 0 : ulong _slot = gui->summary.slot_completed-i;
324 0 : fd_gui_slot_t * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
325 :
326 0 : if( FD_UNLIKELY( slot->slot!=_slot ) ) break;
327 0 : if( FD_UNLIKELY( slot->skipped ) ) jsonp_ulong( gui->http, NULL, slot->slot );
328 0 : }
329 0 : jsonp_close_array( gui->http );
330 0 : jsonp_close_envelope( gui->http );
331 0 : }
332 :
333 : void
334 0 : fd_gui_printf_tps_history( fd_gui_t * gui ) {
335 0 : jsonp_open_envelope( gui->http, "summary", "tps_history" );
336 0 : jsonp_open_array( gui->http, "value" );
337 :
338 0 : for( ulong i=0UL; i<FD_GUI_TPS_HISTORY_SAMPLE_CNT; i++ ) {
339 0 : ulong idx = (gui->summary.estimated_tps_history_idx+i) % FD_GUI_TPS_HISTORY_SAMPLE_CNT;
340 0 : jsonp_open_array( gui->http, NULL );
341 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ][ 0 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
342 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ][ 1 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
343 0 : jsonp_double( gui->http, NULL, (double)(gui->summary.estimated_tps_history[ idx ][ 0 ] - gui->summary.estimated_tps_history[ idx ][ 1 ] - gui->summary.estimated_tps_history[ idx ][ 2 ])/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
344 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ][ 2 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
345 0 : jsonp_close_array( gui->http );
346 0 : }
347 :
348 0 : jsonp_close_array( gui->http );
349 0 : jsonp_close_envelope( gui->http );
350 0 : }
351 :
352 : void
353 0 : fd_gui_printf_startup_progress( fd_gui_t * gui ) {
354 0 : char const * phase;
355 :
356 0 : switch( gui->summary.startup_progress.phase ) {
357 0 : case FD_GUI_START_PROGRESS_TYPE_INITIALIZING:
358 0 : phase = "initializing";
359 0 : break;
360 0 : case FD_GUI_START_PROGRESS_TYPE_SEARCHING_FOR_FULL_SNAPSHOT:
361 0 : phase = "searching_for_full_snapshot";
362 0 : break;
363 0 : case FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT:
364 0 : phase = "downloading_full_snapshot";
365 0 : break;
366 0 : case FD_GUI_START_PROGRESS_TYPE_SEARCHING_FOR_INCREMENTAL_SNAPSHOT:
367 0 : phase = "searching_for_incremental_snapshot";
368 0 : break;
369 0 : case FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT:
370 0 : phase = "downloading_incremental_snapshot";
371 0 : break;
372 0 : case FD_GUI_START_PROGRESS_TYPE_CLEANING_BLOCK_STORE:
373 0 : phase = "cleaning_blockstore";
374 0 : break;
375 0 : case FD_GUI_START_PROGRESS_TYPE_CLEANING_ACCOUNTS:
376 0 : phase = "cleaning_accounts";
377 0 : break;
378 0 : case FD_GUI_START_PROGRESS_TYPE_LOADING_LEDGER:
379 0 : phase = "loading_ledger";
380 0 : break;
381 0 : case FD_GUI_START_PROGRESS_TYPE_PROCESSING_LEDGER:
382 0 : phase = "processing_ledger";
383 0 : break;
384 0 : case FD_GUI_START_PROGRESS_TYPE_STARTING_SERVICES:
385 0 : phase = "starting_services";
386 0 : break;
387 0 : case FD_GUI_START_PROGRESS_TYPE_HALTED:
388 0 : phase = "halted";
389 0 : break;
390 0 : case FD_GUI_START_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY:
391 0 : phase = "waiting_for_supermajority";
392 0 : break;
393 0 : case FD_GUI_START_PROGRESS_TYPE_RUNNING:
394 0 : phase = "running";
395 0 : break;
396 0 : default:
397 0 : FD_LOG_ERR(( "unknown phase %d", gui->summary.startup_progress.phase ));
398 0 : }
399 :
400 0 : jsonp_open_envelope( gui->http, "summary", "startup_progress" );
401 0 : jsonp_open_object( gui->http, "value" );
402 0 : jsonp_string( gui->http, "phase", phase );
403 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT) ) {
404 0 : char peer_addr[ 64 ];
405 0 : FD_TEST( fd_cstr_printf_check( peer_addr, sizeof(peer_addr), NULL, FD_IP4_ADDR_FMT ":%u", FD_IP4_ADDR_FMT_ARGS(gui->summary.startup_progress.startup_full_snapshot_peer_ip_addr), gui->summary.startup_progress.startup_full_snapshot_peer_port ) );
406 :
407 0 : jsonp_string( gui->http, "downloading_full_snapshot_peer", peer_addr );
408 0 : jsonp_ulong( gui->http, "downloading_full_snapshot_slot", gui->summary.startup_progress.startup_full_snapshot_slot );
409 0 : jsonp_double( gui->http, "downloading_full_snapshot_elapsed_secs", gui->summary.startup_progress.startup_full_snapshot_elapsed_secs );
410 0 : jsonp_double( gui->http, "downloading_full_snapshot_remaining_secs", gui->summary.startup_progress.startup_full_snapshot_remaining_secs );
411 0 : jsonp_double( gui->http, "downloading_full_snapshot_throughput", gui->summary.startup_progress.startup_full_snapshot_throughput );
412 0 : jsonp_ulong( gui->http, "downloading_full_snapshot_total_bytes", gui->summary.startup_progress.startup_full_snapshot_total_bytes );
413 0 : jsonp_ulong( gui->http, "downloading_full_snapshot_current_bytes", gui->summary.startup_progress.startup_full_snapshot_current_bytes );
414 0 : } else {
415 0 : jsonp_null( gui->http, "downloading_full_snapshot_peer" );
416 0 : jsonp_null( gui->http, "downloading_full_snapshot_slot" );
417 0 : jsonp_null( gui->http, "downloading_full_snapshot_elapsed_secs" );
418 0 : jsonp_null( gui->http, "downloading_full_snapshot_remaining_secs" );
419 0 : jsonp_null( gui->http, "downloading_full_snapshot_throughput" );
420 0 : jsonp_null( gui->http, "downloading_full_snapshot_total_bytes" );
421 0 : jsonp_null( gui->http, "downloading_full_snapshot_current_bytes" );
422 0 : }
423 :
424 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT) ) {
425 0 : char peer_addr[ 64 ];
426 0 : FD_TEST( fd_cstr_printf_check( peer_addr, sizeof(peer_addr), NULL, FD_IP4_ADDR_FMT ":%u", FD_IP4_ADDR_FMT_ARGS(gui->summary.startup_progress.startup_incremental_snapshot_peer_ip_addr), gui->summary.startup_progress.startup_incremental_snapshot_peer_port ) );
427 :
428 0 : jsonp_string( gui->http, "downloading_incremental_snapshot_peer", peer_addr );
429 0 : jsonp_ulong( gui->http, "downloading_incremental_snapshot_slot", gui->summary.startup_progress.startup_incremental_snapshot_slot );
430 0 : jsonp_double( gui->http, "downloading_incremental_snapshot_elapsed_secs", gui->summary.startup_progress.startup_incremental_snapshot_elapsed_secs );
431 0 : jsonp_double( gui->http, "downloading_incremental_snapshot_remaining_secs", gui->summary.startup_progress.startup_incremental_snapshot_remaining_secs );
432 0 : jsonp_double( gui->http, "downloading_incremental_snapshot_throughput", gui->summary.startup_progress.startup_incremental_snapshot_throughput );
433 0 : jsonp_ulong( gui->http, "downloading_incremental_snapshot_total_bytes", gui->summary.startup_progress.startup_incremental_snapshot_total_bytes );
434 0 : jsonp_ulong( gui->http, "downloading_incremental_snapshot_current_bytes", gui->summary.startup_progress.startup_incremental_snapshot_current_bytes );
435 0 : } else {
436 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_peer" );
437 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_slot" );
438 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_elapsed_secs" );
439 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_remaining_secs" );
440 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_throughput" );
441 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_total_bytes" );
442 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_current_bytes" );
443 0 : }
444 :
445 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUI_START_PROGRESS_TYPE_PROCESSING_LEDGER) ) {
446 0 : jsonp_ulong( gui->http, "ledger_slot", gui->summary.startup_progress.startup_ledger_slot );
447 0 : jsonp_ulong( gui->http, "ledger_max_slot", gui->summary.startup_progress.startup_ledger_max_slot );
448 0 : } else {
449 0 : jsonp_null( gui->http, "ledger_slot" );
450 0 : jsonp_null( gui->http, "ledger_max_slot" );
451 0 : }
452 :
453 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUI_START_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY ) && gui->summary.startup_progress.startup_waiting_for_supermajority_slot!=ULONG_MAX ) {
454 0 : jsonp_ulong( gui->http, "waiting_for_supermajority_slot", gui->summary.startup_progress.startup_waiting_for_supermajority_slot );
455 0 : jsonp_ulong( gui->http, "waiting_for_supermajority_stake_percent", gui->summary.startup_progress.startup_waiting_for_supermajority_stake_pct );
456 0 : } else {
457 0 : jsonp_null( gui->http, "waiting_for_supermajority_slot" );
458 0 : jsonp_null( gui->http, "waiting_for_supermajority_stake_percent" );
459 0 : }
460 0 : jsonp_close_object( gui->http );
461 0 : jsonp_close_envelope( gui->http );
462 0 : }
463 :
464 : void
465 0 : fd_gui_printf_block_engine( fd_gui_t * gui ) {
466 0 : jsonp_open_envelope( gui->http, "block_engine", "update" );
467 0 : jsonp_open_object( gui->http, "value" );
468 0 : jsonp_string( gui->http, "name", gui->block_engine.name );
469 0 : jsonp_string( gui->http, "url", gui->block_engine.url );
470 0 : jsonp_string( gui->http, "ip", gui->block_engine.ip_cstr );
471 0 : if( FD_LIKELY( gui->block_engine.status==1 ) ) jsonp_string( gui->http, "status", "connecting" );
472 0 : else if( FD_LIKELY( gui->block_engine.status==2 ) ) jsonp_string( gui->http, "status", "connected" );
473 0 : else jsonp_string( gui->http, "status", "disconnected" );
474 0 : jsonp_close_object( gui->http );
475 0 : jsonp_close_envelope( gui->http );
476 0 : }
477 :
478 : void
479 0 : fd_gui_printf_tiles( fd_gui_t * gui ) {
480 0 : jsonp_open_envelope( gui->http, "summary", "tiles" );
481 0 : jsonp_open_array( gui->http, "value" );
482 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
483 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
484 :
485 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
486 : /* bench tiles not reported */
487 0 : continue;
488 0 : }
489 :
490 0 : jsonp_open_object( gui->http, NULL );
491 0 : jsonp_string( gui->http, "kind", tile->name );
492 0 : jsonp_ulong( gui->http, "kind_id", tile->kind_id );
493 0 : jsonp_close_object( gui->http );
494 0 : }
495 0 : jsonp_close_array( gui->http );
496 0 : jsonp_close_envelope( gui->http );
497 0 : }
498 :
499 : void
500 0 : fd_gui_printf_schedule_strategy( fd_gui_t * gui ) {
501 0 : jsonp_open_envelope( gui->http, "summary", "schedule_strategy" );
502 0 : char mode[10];
503 0 : switch (gui->summary.schedule_strategy) {
504 0 : case 0: strncpy( mode, "perf", sizeof(mode) ); break;
505 0 : case 1: strncpy( mode, "balanced", sizeof(mode) ); break;
506 0 : case 2: strncpy( mode, "revenue", sizeof(mode) ); break;
507 0 : default: FD_LOG_ERR(("unexpected schedule_strategy %d", gui->summary.schedule_strategy));
508 0 : }
509 0 : mode[ sizeof(mode) - 1] = '\0';
510 0 : jsonp_string( gui->http, "value", mode );
511 0 : jsonp_close_envelope( gui->http );
512 0 : }
513 :
514 : void
515 0 : fd_gui_printf_identity_balance( fd_gui_t * gui ) {
516 0 : jsonp_open_envelope( gui->http, "summary", "identity_balance" );
517 0 : jsonp_ulong_as_str( gui->http, "value", gui->summary.identity_account_balance );
518 0 : jsonp_close_envelope( gui->http );
519 0 : }
520 :
521 : void
522 0 : fd_gui_printf_vote_balance( fd_gui_t * gui ) {
523 0 : jsonp_open_envelope( gui->http, "summary", "vote_balance" );
524 0 : jsonp_ulong_as_str( gui->http, "value", gui->summary.vote_account_balance );
525 0 : jsonp_close_envelope( gui->http );
526 0 : }
527 :
528 : void
529 0 : fd_gui_printf_estimated_slot_duration_nanos( fd_gui_t * gui ) {
530 0 : jsonp_open_envelope( gui->http, "summary", "estimated_slot_duration_nanos" );
531 0 : jsonp_ulong( gui->http, "value", gui->summary.estimated_slot_duration_nanos );
532 0 : jsonp_close_envelope( gui->http );
533 0 : }
534 :
535 :
536 : void
537 0 : fd_gui_printf_root_slot( fd_gui_t * gui ) {
538 0 : jsonp_open_envelope( gui->http, "summary", "root_slot" );
539 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_rooted!=ULONG_MAX, gui->summary.slot_rooted, 0UL ) );
540 0 : jsonp_close_envelope( gui->http );
541 0 : }
542 :
543 : void
544 0 : fd_gui_printf_optimistically_confirmed_slot( fd_gui_t * gui ) {
545 0 : jsonp_open_envelope( gui->http, "summary", "optimistically_confirmed_slot" );
546 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_optimistically_confirmed!=ULONG_MAX, gui->summary.slot_optimistically_confirmed, 0UL ) );
547 0 : jsonp_close_envelope( gui->http );
548 0 : }
549 :
550 : void
551 0 : fd_gui_printf_completed_slot( fd_gui_t * gui ) {
552 0 : jsonp_open_envelope( gui->http, "summary", "completed_slot" );
553 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_completed!=ULONG_MAX, gui->summary.slot_completed, 0UL ) );
554 0 : jsonp_close_envelope( gui->http );
555 0 : }
556 :
557 : void
558 0 : fd_gui_printf_estimated_slot( fd_gui_t * gui ) {
559 0 : jsonp_open_envelope( gui->http, "summary", "estimated_slot" );
560 0 : jsonp_ulong( gui->http, "value", fd_ulong_if( gui->summary.slot_estimated!=ULONG_MAX, gui->summary.slot_estimated, 0UL ) );
561 0 : jsonp_close_envelope( gui->http );
562 0 : }
563 :
564 : void
565 : fd_gui_printf_skip_rate( fd_gui_t * gui,
566 0 : ulong epoch_idx ) {
567 0 : jsonp_open_envelope( gui->http, "summary", "skip_rate" );
568 0 : jsonp_open_object( gui->http, "value" );
569 0 : jsonp_ulong( gui->http, "epoch", gui->epoch.epochs[ epoch_idx ].epoch );
570 0 : if( FD_UNLIKELY( !gui->epoch.epochs[ epoch_idx ].my_total_slots ) ) jsonp_double( gui->http, "skip_rate", 0.0 );
571 0 : else jsonp_double( gui->http, "skip_rate", (double)gui->epoch.epochs[ epoch_idx ].my_skipped_slots/(double)gui->epoch.epochs[ epoch_idx ].my_total_slots );
572 0 : jsonp_close_object( gui->http );
573 0 : jsonp_close_envelope( gui->http );
574 0 : }
575 :
576 : void
577 : fd_gui_printf_epoch( fd_gui_t * gui,
578 0 : ulong epoch_idx ) {
579 0 : jsonp_open_envelope( gui->http, "epoch", "new" );
580 0 : jsonp_open_object( gui->http, "value" );
581 0 : jsonp_ulong( gui->http, "epoch", gui->epoch.epochs[ epoch_idx ].epoch );
582 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 );
583 0 : else jsonp_null( gui->http, "start_time_nanos" );
584 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 );
585 0 : else jsonp_null( gui->http, "end_time_nanos" );
586 0 : jsonp_ulong( gui->http, "start_slot", gui->epoch.epochs[ epoch_idx ].start_slot );
587 0 : jsonp_ulong( gui->http, "end_slot", gui->epoch.epochs[ epoch_idx ].end_slot );
588 0 : jsonp_ulong_as_str( gui->http, "excluded_stake_lamports", gui->epoch.epochs[ epoch_idx ].excluded_stake );
589 0 : jsonp_open_array( gui->http, "staked_pubkeys" );
590 0 : fd_epoch_leaders_t * lsched = gui->epoch.epochs[epoch_idx].lsched;
591 0 : for( ulong i=0UL; i<lsched->pub_cnt; i++ ) {
592 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
593 0 : fd_base58_encode_32( lsched->pub[ i ].uc, NULL, identity_base58 );
594 0 : jsonp_string( gui->http, NULL, identity_base58 );
595 0 : }
596 0 : jsonp_close_array( gui->http );
597 :
598 0 : jsonp_open_array( gui->http, "staked_lamports" );
599 0 : fd_vote_stake_weight_t * stakes = gui->epoch.epochs[epoch_idx].stakes;
600 0 : for( ulong i=0UL; i<lsched->pub_cnt; i++ ) jsonp_ulong_as_str( gui->http, NULL, stakes[ i ].stake );
601 0 : jsonp_close_array( gui->http );
602 :
603 0 : jsonp_open_array( gui->http, "leader_slots" );
604 0 : for( ulong i = 0; i < lsched->sched_cnt; i++ ) jsonp_ulong( gui->http, NULL, lsched->sched[ i ] );
605 0 : jsonp_close_array( gui->http );
606 0 : jsonp_close_object( gui->http );
607 0 : jsonp_close_envelope( gui->http );
608 0 : }
609 :
610 : static void
611 : fd_gui_printf_waterfall( fd_gui_t * gui,
612 : fd_gui_txn_waterfall_t const * prev,
613 0 : fd_gui_txn_waterfall_t const * cur ) {
614 0 : jsonp_open_object( gui->http, "waterfall" );
615 0 : jsonp_open_object( gui->http, "in" );
616 0 : jsonp_ulong( gui->http, "pack_cranked", cur->in.pack_cranked - prev->in.pack_cranked );
617 0 : jsonp_ulong( gui->http, "pack_retained", prev->out.pack_retained );
618 0 : jsonp_ulong( gui->http, "resolv_retained", prev->out.resolv_retained );
619 0 : jsonp_ulong( gui->http, "quic", cur->in.quic - prev->in.quic );
620 0 : jsonp_ulong( gui->http, "udp", cur->in.udp - prev->in.udp );
621 0 : jsonp_ulong( gui->http, "gossip", cur->in.gossip - prev->in.gossip );
622 0 : jsonp_ulong( gui->http, "block_engine", cur->in.block_engine - prev->in.block_engine );
623 0 : jsonp_close_object( gui->http );
624 :
625 0 : jsonp_open_object( gui->http, "out" );
626 0 : jsonp_ulong( gui->http, "net_overrun", cur->out.net_overrun - prev->out.net_overrun );
627 0 : jsonp_ulong( gui->http, "quic_overrun", cur->out.quic_overrun - prev->out.quic_overrun );
628 0 : jsonp_ulong( gui->http, "quic_frag_drop", cur->out.quic_frag_drop - prev->out.quic_frag_drop );
629 0 : jsonp_ulong( gui->http, "quic_abandoned", cur->out.quic_abandoned - prev->out.quic_abandoned );
630 0 : jsonp_ulong( gui->http, "tpu_quic_invalid", cur->out.tpu_quic_invalid - prev->out.tpu_quic_invalid );
631 0 : jsonp_ulong( gui->http, "tpu_udp_invalid", cur->out.tpu_udp_invalid - prev->out.tpu_udp_invalid );
632 0 : jsonp_ulong( gui->http, "verify_overrun", cur->out.verify_overrun - prev->out.verify_overrun );
633 0 : jsonp_ulong( gui->http, "verify_parse", cur->out.verify_parse - prev->out.verify_parse );
634 0 : jsonp_ulong( gui->http, "verify_failed", cur->out.verify_failed - prev->out.verify_failed );
635 0 : jsonp_ulong( gui->http, "verify_duplicate", cur->out.verify_duplicate - prev->out.verify_duplicate );
636 0 : jsonp_ulong( gui->http, "dedup_duplicate", cur->out.dedup_duplicate - prev->out.dedup_duplicate );
637 0 : jsonp_ulong( gui->http, "resolv_lut_failed", cur->out.resolv_lut_failed - prev->out.resolv_lut_failed );
638 0 : jsonp_ulong( gui->http, "resolv_expired", cur->out.resolv_expired - prev->out.resolv_expired );
639 0 : jsonp_ulong( gui->http, "resolv_ancient", cur->out.resolv_ancient - prev->out.resolv_ancient );
640 0 : jsonp_ulong( gui->http, "resolv_no_ledger", cur->out.resolv_no_ledger - prev->out.resolv_no_ledger );
641 0 : jsonp_ulong( gui->http, "resolv_retained", cur->out.resolv_retained );
642 0 : jsonp_ulong( gui->http, "pack_invalid", cur->out.pack_invalid - prev->out.pack_invalid );
643 0 : jsonp_ulong( gui->http, "pack_invalid_bundle", cur->out.pack_invalid_bundle - prev->out.pack_invalid_bundle );
644 0 : jsonp_ulong( gui->http, "pack_expired", cur->out.pack_expired - prev->out.pack_expired );
645 0 : jsonp_ulong( gui->http, "pack_retained", cur->out.pack_retained );
646 0 : jsonp_ulong( gui->http, "pack_wait_full", cur->out.pack_wait_full - prev->out.pack_wait_full );
647 0 : jsonp_ulong( gui->http, "pack_leader_slow", cur->out.pack_leader_slow - prev->out.pack_leader_slow );
648 0 : jsonp_ulong( gui->http, "bank_invalid", cur->out.bank_invalid - prev->out.bank_invalid );
649 0 : jsonp_ulong( gui->http, "block_success", cur->out.block_success - prev->out.block_success );
650 0 : jsonp_ulong( gui->http, "block_fail", cur->out.block_fail - prev->out.block_fail );
651 0 : jsonp_close_object( gui->http );
652 0 : jsonp_close_object( gui->http );
653 0 : }
654 :
655 : void
656 : fd_gui_printf_live_txn_waterfall( fd_gui_t * gui,
657 : fd_gui_txn_waterfall_t const * prev,
658 : fd_gui_txn_waterfall_t const * cur,
659 0 : ulong next_leader_slot ) {
660 0 : jsonp_open_envelope( gui->http, "summary", "live_txn_waterfall" );
661 0 : jsonp_open_object( gui->http, "value" );
662 0 : jsonp_ulong( gui->http, "next_leader_slot", next_leader_slot );
663 0 : fd_gui_printf_waterfall( gui, prev, cur );
664 0 : jsonp_close_object( gui->http );
665 0 : jsonp_close_envelope( gui->http );
666 0 : }
667 :
668 : static void
669 : fd_gui_printf_tile_stats( fd_gui_t * gui,
670 : fd_gui_tile_stats_t const * prev,
671 0 : fd_gui_tile_stats_t const * cur ) {
672 0 : jsonp_open_object( gui->http, "tile_primary_metric" );
673 0 : jsonp_ulong( gui->http, "quic", cur->quic_conn_cnt );
674 0 : jsonp_double( gui->http, "bundle_rtt_smoothed_millis", (double)(cur->bundle_rtt_smoothed_nanos) / 1000000.0 );
675 :
676 0 : fd_histf_t bundle_rx_delay_hist_delta[ 1 ];
677 0 : fd_histf_subtract( &cur->bundle_rx_delay_hist, &prev->bundle_rx_delay_hist, bundle_rx_delay_hist_delta );
678 0 : ulong bundle_rx_delay_nanos_p90 = fd_histf_percentile( bundle_rx_delay_hist_delta, 90U, ULONG_MAX );
679 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 ));
680 :
681 0 : if( FD_LIKELY( cur->sample_time_nanos>prev->sample_time_nanos ) ) {
682 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) ));
683 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) ));
684 0 : } else {
685 0 : jsonp_ulong( gui->http, "net_in", 0 );
686 0 : jsonp_ulong( gui->http, "net_out", 0 );
687 0 : }
688 0 : if( FD_LIKELY( cur->verify_total_cnt>prev->verify_total_cnt ) ) {
689 0 : jsonp_double( gui->http, "verify", (double)(cur->verify_drop_cnt-prev->verify_drop_cnt) / (double)(cur->verify_total_cnt-prev->verify_total_cnt) );
690 0 : } else {
691 0 : jsonp_double( gui->http, "verify", 0.0 );
692 0 : }
693 0 : if( FD_LIKELY( cur->dedup_total_cnt>prev->dedup_total_cnt ) ) {
694 0 : jsonp_double( gui->http, "dedup", (double)(cur->dedup_drop_cnt-prev->dedup_drop_cnt) / (double)(cur->dedup_total_cnt-prev->dedup_total_cnt) );
695 0 : } else {
696 0 : jsonp_double( gui->http, "dedup", 0.0 );
697 0 : }
698 0 : jsonp_ulong( gui->http, "bank", cur->bank_txn_exec_cnt - prev->bank_txn_exec_cnt );
699 0 : jsonp_double( gui->http, "pack", !cur->pack_buffer_capacity ? 1.0 : (double)cur->pack_buffer_cnt/(double)cur->pack_buffer_capacity );
700 0 : jsonp_double( gui->http, "poh", 0.0 );
701 0 : jsonp_double( gui->http, "shred", 0.0 );
702 0 : jsonp_double( gui->http, "store", 0.0 );
703 0 : jsonp_close_object( gui->http );
704 0 : }
705 :
706 : void
707 : fd_gui_printf_live_tile_stats( fd_gui_t * gui,
708 : fd_gui_tile_stats_t const * prev,
709 0 : fd_gui_tile_stats_t const * cur ) {
710 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_primary_metric" );
711 0 : jsonp_open_object( gui->http, "value" );
712 0 : jsonp_ulong( gui->http, "next_leader_slot", 0UL );
713 0 : fd_gui_printf_tile_stats( 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_tile_timers( fd_gui_t * gui,
720 : fd_gui_tile_timers_t const * prev,
721 0 : fd_gui_tile_timers_t const * cur ) {
722 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
723 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
724 :
725 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
726 : /* bench tiles not reported */
727 0 : continue;
728 0 : }
729 :
730 0 : double cur_total = (double)(cur[ i ].caughtup_housekeeping_ticks
731 0 : + cur[ i ].processing_housekeeping_ticks
732 0 : + cur[ i ].backpressure_housekeeping_ticks
733 0 : + cur[ i ].caughtup_prefrag_ticks
734 0 : + cur[ i ].processing_prefrag_ticks
735 0 : + cur[ i ].backpressure_prefrag_ticks
736 0 : + cur[ i ].caughtup_postfrag_ticks
737 0 : + cur[ i ].processing_postfrag_ticks);
738 :
739 0 : double prev_total = (double)(prev[ i ].caughtup_housekeeping_ticks
740 0 : + prev[ i ].processing_housekeeping_ticks
741 0 : + prev[ i ].backpressure_housekeeping_ticks
742 0 : + prev[ i ].caughtup_prefrag_ticks
743 0 : + prev[ i ].processing_prefrag_ticks
744 0 : + prev[ i ].backpressure_prefrag_ticks
745 0 : + prev[ i ].caughtup_postfrag_ticks
746 0 : + prev[ i ].processing_postfrag_ticks);
747 :
748 0 : double idle;
749 0 : if( FD_UNLIKELY( cur_total==prev_total ) ) {
750 : /* The tile didn't sample timers since the last sample, unclear what
751 : idleness should be so send -1. NaN would be better but no NaN in
752 : JSON. */
753 0 : idle = -1;
754 0 : } else {
755 0 : idle = (double)(cur[ i ].caughtup_postfrag_ticks - prev[ i ].caughtup_postfrag_ticks) / (cur_total - prev_total);
756 0 : }
757 :
758 0 : jsonp_double( gui->http, NULL, idle );
759 0 : }
760 0 : }
761 :
762 : void
763 0 : fd_gui_printf_live_tile_timers( fd_gui_t * gui ) {
764 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_timers" );
765 0 : jsonp_open_array( gui->http, "value" );
766 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 ];
767 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 ];
768 0 : fd_gui_printf_tile_timers( gui, prev, cur );
769 0 : jsonp_close_array( gui->http );
770 0 : jsonp_close_envelope( gui->http );
771 0 : }
772 :
773 : void
774 0 : fd_gui_printf_estimated_tps( fd_gui_t * gui ) {
775 0 : ulong idx = (gui->summary.estimated_tps_history_idx+FD_GUI_TPS_HISTORY_SAMPLE_CNT-1UL) % FD_GUI_TPS_HISTORY_SAMPLE_CNT;
776 :
777 0 : jsonp_open_envelope( gui->http, "summary", "estimated_tps" );
778 0 : jsonp_open_object( gui->http, "value" );
779 0 : jsonp_double( gui->http, "total", (double)gui->summary.estimated_tps_history[ idx ][ 0 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
780 0 : jsonp_double( gui->http, "vote", (double)gui->summary.estimated_tps_history[ idx ][ 1 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
781 0 : jsonp_double( gui->http, "nonvote_success", (double)(gui->summary.estimated_tps_history[ idx ][ 0 ] - gui->summary.estimated_tps_history[ idx ][ 1 ] - gui->summary.estimated_tps_history[ idx ][ 2 ])/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
782 0 : jsonp_double( gui->http, "nonvote_failed", (double)gui->summary.estimated_tps_history[ idx ][ 2 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
783 0 : jsonp_close_object( gui->http );
784 0 : jsonp_close_envelope( gui->http );
785 0 : }
786 :
787 : static int
788 : fd_gui_gossip_contains( fd_gui_t const * gui,
789 0 : uchar const * pubkey ) {
790 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
791 0 : if( FD_UNLIKELY( !memcmp( gui->gossip.peers[ i ].pubkey->uc, pubkey, 32 ) ) ) return 1;
792 0 : }
793 0 : return 0;
794 0 : }
795 :
796 : static int
797 : fd_gui_vote_acct_contains( fd_gui_t const * gui,
798 0 : uchar const * pubkey ) {
799 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
800 0 : if( FD_UNLIKELY( !memcmp( gui->vote_account.vote_accounts[ i ].pubkey, pubkey, 32 ) ) ) return 1;
801 0 : }
802 0 : return 0;
803 0 : }
804 :
805 : static int
806 : fd_gui_validator_info_contains( fd_gui_t const * gui,
807 0 : uchar const * pubkey ) {
808 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
809 0 : if( FD_UNLIKELY( !memcmp( gui->validator_info.info[ i ].pubkey, pubkey, 32 ) ) ) return 1;
810 0 : }
811 0 : return 0;
812 0 : }
813 :
814 : static void
815 : fd_gui_printf_peer( fd_gui_t * gui,
816 0 : uchar const * identity_pubkey ) {
817 0 : ulong gossip_idx = ULONG_MAX;
818 0 : ulong info_idx = ULONG_MAX;
819 0 : ulong vote_idxs[ FD_GUI_MAX_PEER_CNT ] = {0};
820 0 : ulong vote_idx_cnt = 0UL;
821 :
822 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
823 0 : if( FD_UNLIKELY( !memcmp( gui->gossip.peers[ i ].pubkey->uc, identity_pubkey, 32 ) ) ) {
824 0 : gossip_idx = i;
825 0 : break;
826 0 : }
827 0 : }
828 :
829 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
830 0 : if( FD_UNLIKELY( !memcmp( gui->validator_info.info[ i ].pubkey, identity_pubkey, 32 ) ) ) {
831 0 : info_idx = i;
832 0 : break;
833 0 : }
834 0 : }
835 :
836 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
837 0 : if( FD_UNLIKELY( !memcmp( gui->vote_account.vote_accounts[ i ].pubkey, identity_pubkey, 32 ) ) ) {
838 0 : vote_idxs[ vote_idx_cnt++ ] = i;
839 0 : }
840 0 : }
841 :
842 0 : jsonp_open_object( gui->http, NULL );
843 :
844 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
845 0 : fd_base58_encode_32( identity_pubkey, NULL, identity_base58 );
846 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
847 :
848 0 : if( FD_UNLIKELY( gossip_idx==ULONG_MAX ) ) {
849 0 : jsonp_string( gui->http, "gossip", NULL );
850 0 : } else {
851 0 : jsonp_open_object( gui->http, "gossip" );
852 :
853 0 : char version[ 32 ];
854 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 ) );
855 0 : jsonp_string( gui->http, "version", version );
856 0 : jsonp_ulong( gui->http, "feature_set", gui->gossip.peers[ gossip_idx ].version.feature_set );
857 0 : jsonp_ulong( gui->http, "wallclock", gui->gossip.peers[ gossip_idx ].wallclock );
858 0 : jsonp_ulong( gui->http, "shred_version", gui->gossip.peers[ gossip_idx ].shred_version );
859 0 : jsonp_open_object( gui->http, "sockets" );
860 0 : for( ulong j=0UL; j<12UL; j++ ) {
861 0 : if( FD_LIKELY( !gui->gossip.peers[ gossip_idx ].sockets[ j ].ipv4 && !gui->gossip.peers[ gossip_idx ].sockets[ j ].port ) ) continue;
862 0 : char const * tag;
863 0 : switch( j ) {
864 0 : case 0: tag = "gossip"; break;
865 0 : case 1: tag = "rpc"; break;
866 0 : case 2: tag = "rpb_pubsub"; break;
867 0 : case 3: tag = "serve_repair"; break;
868 0 : case 4: tag = "serve_repair_quic"; break;
869 0 : case 5: tag = "tpu"; break;
870 0 : case 6: tag = "tpu_quic"; break;
871 0 : case 7: tag = "tvu"; break;
872 0 : case 8: tag = "tvu_quic"; break;
873 0 : case 9: tag = "tpu_forwards"; break;
874 0 : case 10: tag = "tpu_forwards_quic"; break;
875 0 : case 11: tag = "tpu_vote"; break;
876 0 : }
877 0 : char line[ 64 ];
878 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 ) );
879 0 : jsonp_string( gui->http, tag, line );
880 0 : }
881 0 : jsonp_close_object( gui->http );
882 :
883 0 : jsonp_close_object( gui->http );
884 0 : }
885 :
886 0 : jsonp_open_array( gui->http, "vote" );
887 0 : for( ulong i=0UL; i<vote_idx_cnt; i++ ) {
888 0 : jsonp_open_object( gui->http, NULL );
889 0 : char vote_account_base58[ FD_BASE58_ENCODED_32_SZ ];
890 0 : fd_base58_encode_32( gui->vote_account.vote_accounts[ vote_idxs[ i ] ].vote_account->uc, NULL, vote_account_base58 );
891 0 : jsonp_string( gui->http, "vote_account", vote_account_base58 );
892 0 : jsonp_ulong_as_str( gui->http, "activated_stake", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].activated_stake );
893 0 : jsonp_ulong( gui->http, "last_vote", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].last_vote );
894 0 : jsonp_ulong( gui->http, "root_slot", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].root_slot );
895 0 : jsonp_ulong( gui->http, "epoch_credits", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].epoch_credits );
896 0 : jsonp_ulong( gui->http, "commission", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].commission );
897 0 : jsonp_bool( gui->http, "delinquent", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].delinquent );
898 0 : jsonp_close_object( gui->http );
899 0 : }
900 0 : jsonp_close_array( gui->http );
901 :
902 0 : if( FD_UNLIKELY( info_idx==ULONG_MAX ) ) {
903 0 : jsonp_string( gui->http, "info", NULL );
904 0 : } else {
905 0 : jsonp_open_object( gui->http, "info" );
906 0 : jsonp_string( gui->http, "name", gui->validator_info.info[ info_idx ].name );
907 0 : jsonp_string( gui->http, "details", gui->validator_info.info[ info_idx ].details );
908 0 : jsonp_string( gui->http, "website", gui->validator_info.info[ info_idx ].website );
909 0 : jsonp_string( gui->http, "icon_url", gui->validator_info.info[ info_idx ].icon_uri );
910 0 : jsonp_close_object( gui->http );
911 0 : }
912 :
913 0 : jsonp_close_object( gui->http );
914 0 : }
915 :
916 : void
917 : fd_gui_printf_peers_gossip_update( fd_gui_t * gui,
918 : ulong const * updated,
919 : ulong updated_cnt,
920 : fd_pubkey_t const * removed,
921 : ulong removed_cnt,
922 : ulong const * added,
923 0 : ulong added_cnt ) {
924 0 : jsonp_open_envelope( gui->http, "peers", "update" );
925 0 : jsonp_open_object( gui->http, "value" );
926 0 : jsonp_open_array( gui->http, "add" );
927 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
928 0 : int actually_added = !fd_gui_vote_acct_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc ) &&
929 0 : !fd_gui_validator_info_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
930 0 : if( FD_LIKELY( !actually_added ) ) continue;
931 :
932 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
933 0 : }
934 0 : jsonp_close_array( gui->http );
935 :
936 0 : jsonp_open_array( gui->http, "update" );
937 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
938 0 : int actually_added = !fd_gui_vote_acct_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc ) &&
939 0 : !fd_gui_validator_info_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
940 0 : if( FD_LIKELY( actually_added ) ) continue;
941 :
942 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
943 0 : }
944 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
945 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ updated[ i ] ].pubkey->uc );
946 0 : }
947 0 : jsonp_close_array( gui->http );
948 :
949 0 : jsonp_open_array( gui->http, "remove" );
950 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
951 0 : int actually_removed = !fd_gui_vote_acct_contains( gui, removed[ i ].uc ) &&
952 0 : !fd_gui_validator_info_contains( gui, removed[ i ].uc );
953 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
954 :
955 0 : jsonp_open_object( gui->http, NULL );
956 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
957 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
958 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
959 0 : jsonp_close_object( gui->http );
960 0 : }
961 0 : jsonp_close_array( gui->http );
962 0 : jsonp_close_object( gui->http );
963 0 : jsonp_close_envelope( gui->http );
964 0 : }
965 :
966 : void
967 : fd_gui_printf_peers_vote_account_update( fd_gui_t * gui,
968 : ulong const * updated,
969 : ulong updated_cnt,
970 : fd_pubkey_t const * removed,
971 : ulong removed_cnt,
972 : ulong const * added,
973 0 : ulong added_cnt ) {
974 0 : jsonp_open_envelope( gui->http, "peers", "update" );
975 0 : jsonp_open_object( gui->http, "value" );
976 0 : jsonp_open_array( gui->http, "add" );
977 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
978 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
979 0 : !fd_gui_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
980 0 : if( FD_LIKELY( !actually_added ) ) continue;
981 :
982 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
983 0 : }
984 0 : jsonp_close_array( gui->http );
985 :
986 0 : jsonp_open_array( gui->http, "update" );
987 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
988 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
989 0 : !fd_gui_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
990 0 : if( FD_LIKELY( actually_added ) ) continue;
991 :
992 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
993 0 : }
994 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
995 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ updated[ i ] ].pubkey->uc );
996 0 : }
997 0 : jsonp_close_array( gui->http );
998 :
999 0 : jsonp_open_array( gui->http, "remove" );
1000 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
1001 0 : int actually_removed = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
1002 0 : !fd_gui_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
1003 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
1004 :
1005 0 : jsonp_open_object( gui->http, NULL );
1006 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1007 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
1008 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
1009 0 : jsonp_close_object( gui->http );
1010 0 : }
1011 0 : jsonp_close_array( gui->http );
1012 0 : jsonp_close_object( gui->http );
1013 0 : jsonp_close_envelope( gui->http );
1014 0 : }
1015 :
1016 : void
1017 : fd_gui_printf_peers_validator_info_update( fd_gui_t * gui,
1018 : ulong const * updated,
1019 : ulong updated_cnt,
1020 : fd_pubkey_t const * removed,
1021 : ulong removed_cnt,
1022 : ulong const * added,
1023 0 : ulong added_cnt ) {
1024 0 : jsonp_open_envelope( gui->http, "peers", "update" );
1025 0 : jsonp_open_object( gui->http, "value" );
1026 0 : jsonp_open_array( gui->http, "add" );
1027 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1028 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
1029 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1030 0 : if( FD_LIKELY( !actually_added ) ) continue;
1031 :
1032 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1033 0 : }
1034 0 : jsonp_close_array( gui->http );
1035 :
1036 0 : jsonp_open_array( gui->http, "update" );
1037 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
1038 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
1039 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1040 0 : if( FD_LIKELY( actually_added ) ) continue;
1041 :
1042 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1043 0 : }
1044 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
1045 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ updated[ i ] ].pubkey->uc );
1046 0 : }
1047 0 : jsonp_close_array( gui->http );
1048 :
1049 0 : jsonp_open_array( gui->http, "remove" );
1050 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
1051 0 : int actually_removed = !fd_gui_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
1052 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1053 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
1054 :
1055 0 : jsonp_open_object( gui->http, NULL );
1056 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1057 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
1058 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
1059 0 : jsonp_close_object( gui->http );
1060 0 : }
1061 0 : jsonp_close_array( gui->http );
1062 0 : jsonp_close_object( gui->http );
1063 0 : jsonp_close_envelope( gui->http );
1064 0 : }
1065 :
1066 : void
1067 0 : fd_gui_printf_peers_all( fd_gui_t * gui ) {
1068 0 : jsonp_open_envelope( gui->http, "peers", "update" );
1069 0 : jsonp_open_object( gui->http, "value" );
1070 0 : jsonp_open_array( gui->http, "add" );
1071 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
1072 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ i ].pubkey->uc );
1073 0 : }
1074 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
1075 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ i ].pubkey->uc );
1076 0 : if( FD_UNLIKELY( actually_added ) ) {
1077 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ i ].pubkey->uc );
1078 0 : }
1079 0 : }
1080 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
1081 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ i ].pubkey->uc ) &&
1082 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ i ].pubkey->uc );
1083 0 : if( FD_UNLIKELY( actually_added ) ) {
1084 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ i ].pubkey->uc );
1085 0 : }
1086 0 : }
1087 0 : jsonp_close_array( gui->http );
1088 0 : jsonp_close_object( gui->http );
1089 0 : jsonp_close_envelope( gui->http );
1090 0 : }
1091 :
1092 : static void
1093 : fd_gui_printf_ts_tile_timers( fd_gui_t * gui,
1094 : fd_gui_tile_timers_t const * prev,
1095 0 : fd_gui_tile_timers_t const * cur ) {
1096 0 : jsonp_open_object( gui->http, NULL );
1097 0 : jsonp_ulong_as_str( gui->http, "timestamp_nanos", 0 );
1098 0 : jsonp_open_array( gui->http, "tile_timers" );
1099 0 : fd_gui_printf_tile_timers( gui, prev, cur );
1100 0 : jsonp_close_array( gui->http );
1101 0 : jsonp_close_object( gui->http );
1102 0 : }
1103 :
1104 : void
1105 : fd_gui_printf_slot( fd_gui_t * gui,
1106 0 : ulong _slot ) {
1107 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
1108 :
1109 0 : char const * level;
1110 0 : switch( slot->level ) {
1111 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1112 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1113 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1114 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1115 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1116 0 : default: level = "unknown"; break;
1117 0 : }
1118 :
1119 0 : fd_gui_slot_t * parent_slot = fd_gui_get_slot( gui, slot->parent_slot );
1120 0 : long duration_nanos = LONG_MAX;
1121 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1122 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1123 0 : }
1124 :
1125 0 : jsonp_open_envelope( gui->http, "slot", "update" );
1126 0 : jsonp_open_object( gui->http, "value" );
1127 0 : jsonp_open_object( gui->http, "publish" );
1128 0 : jsonp_ulong( gui->http, "slot", _slot );
1129 0 : jsonp_bool( gui->http, "mine", slot->mine );
1130 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1131 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1132 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1133 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1134 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
1135 0 : jsonp_string( gui->http, "level", level );
1136 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX
1137 0 : || slot->vote_txn_cnt==UINT_MAX
1138 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1139 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->total_txn_cnt - slot->vote_txn_cnt - slot->nonvote_failed_txn_cnt );
1140 0 : if( FD_UNLIKELY( slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1141 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed_txn_cnt );
1142 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX
1143 0 : || slot->failed_txn_cnt==UINT_MAX
1144 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1145 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_txn_cnt - (slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt) );
1146 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX
1147 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1148 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt );
1149 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1150 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1151 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1152 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1153 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
1154 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
1155 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1156 0 : else jsonp_ulong_as_str( gui->http, "transaction_fee", slot->transaction_fee );
1157 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1158 0 : else jsonp_ulong_as_str( gui->http, "priority_fee", slot->priority_fee );
1159 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1160 0 : else jsonp_ulong_as_str( gui->http, "tips", slot->tips );
1161 0 : jsonp_close_object( gui->http );
1162 0 : jsonp_close_object( gui->http );
1163 0 : jsonp_close_envelope( gui->http );
1164 0 : }
1165 :
1166 : void
1167 : fd_gui_printf_summary_ping( fd_gui_t * gui,
1168 0 : ulong id ) {
1169 0 : jsonp_open_envelope( gui->http, "summary", "ping" );
1170 0 : jsonp_ulong( gui->http, "id", id );
1171 0 : jsonp_null( gui->http, "value" );
1172 0 : jsonp_close_envelope( gui->http );
1173 0 : }
1174 :
1175 : void
1176 : fd_gui_printf_slot_rankings_request( fd_gui_t * gui,
1177 : ulong id,
1178 0 : int mine ) {
1179 0 : ulong epoch = ULONG_MAX;
1180 0 : for( ulong i = 0UL; i<2UL; i++ ) {
1181 0 : if( FD_LIKELY( gui->epoch.has_epoch[ i ] ) ) {
1182 : /* the "current" epoch is the smallest */
1183 0 : epoch = fd_ulong_min( epoch, gui->epoch.epochs[ i ].epoch );
1184 0 : }
1185 0 : }
1186 0 : ulong epoch_idx = epoch % 2UL;
1187 :
1188 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 );
1189 :
1190 0 : jsonp_open_envelope( gui->http, "slot", "query_rankings" );
1191 0 : jsonp_ulong( gui->http, "id", id );
1192 0 : jsonp_open_object( gui->http, "value" );
1193 :
1194 0 : #define OUTPUT_RANKING_ARRAY(field) \
1195 0 : jsonp_open_array( gui->http, "slots_" FD_STRINGIFY(field) ); \
1196 0 : for( ulong i = 0UL; i<fd_ulong_if( epoch==ULONG_MAX, 0UL, FD_GUI_SLOT_RANKINGS_SZ ); i++ ) { \
1197 0 : if( FD_UNLIKELY( rankings->field[ i ].slot==ULONG_MAX ) ) break; \
1198 0 : jsonp_ulong( gui->http, NULL, rankings->field[ i ].slot ); \
1199 0 : } \
1200 0 : jsonp_close_array( gui->http ); \
1201 0 : jsonp_open_array( gui->http, "vals_" FD_STRINGIFY(field) ); \
1202 0 : for( ulong i = 0UL; i<fd_ulong_if( epoch==ULONG_MAX, 0UL, FD_GUI_SLOT_RANKINGS_SZ ); i++ ) { \
1203 0 : if( FD_UNLIKELY( rankings->field[ i ].slot==ULONG_MAX ) ) break; \
1204 0 : jsonp_ulong( gui->http, NULL, rankings->field[ i ].value ); \
1205 0 : } \
1206 0 : jsonp_close_array( gui->http )
1207 :
1208 0 : OUTPUT_RANKING_ARRAY( largest_tips );
1209 0 : OUTPUT_RANKING_ARRAY( largest_fees );
1210 0 : OUTPUT_RANKING_ARRAY( largest_rewards );
1211 0 : OUTPUT_RANKING_ARRAY( largest_duration );
1212 0 : OUTPUT_RANKING_ARRAY( largest_compute_units );
1213 0 : OUTPUT_RANKING_ARRAY( largest_skipped );
1214 0 : OUTPUT_RANKING_ARRAY( smallest_tips );
1215 0 : OUTPUT_RANKING_ARRAY( smallest_fees );
1216 0 : OUTPUT_RANKING_ARRAY( smallest_rewards );
1217 0 : OUTPUT_RANKING_ARRAY( smallest_duration );
1218 0 : OUTPUT_RANKING_ARRAY( smallest_compute_units );
1219 0 : OUTPUT_RANKING_ARRAY( smallest_skipped );
1220 :
1221 0 : #undef OUTPUT_RANKING_ARRAY
1222 :
1223 0 : jsonp_close_object( gui->http );
1224 0 : jsonp_close_envelope( gui->http );
1225 0 : }
1226 :
1227 : void
1228 : fd_gui_printf_slot_request( fd_gui_t * gui,
1229 : ulong _slot,
1230 0 : ulong id ) {
1231 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
1232 :
1233 0 : char const * level;
1234 0 : switch( slot->level ) {
1235 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1236 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1237 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1238 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1239 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1240 0 : default: level = "unknown"; break;
1241 0 : }
1242 :
1243 0 : fd_gui_slot_t * parent_slot = fd_gui_get_slot( gui, slot->parent_slot );
1244 0 : long duration_nanos = LONG_MAX;
1245 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1246 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1247 0 : }
1248 :
1249 0 : jsonp_open_envelope( gui->http, "slot", "query" );
1250 0 : jsonp_ulong( gui->http, "id", id );
1251 0 : jsonp_open_object( gui->http, "value" );
1252 :
1253 0 : jsonp_open_object( gui->http, "publish" );
1254 0 : jsonp_ulong( gui->http, "slot", _slot );
1255 0 : jsonp_bool( gui->http, "mine", slot->mine );
1256 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1257 0 : jsonp_string( gui->http, "level", level );
1258 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1259 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1260 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1261 0 : else jsonp_long( gui->http, "completed_time_nanos", slot->completed_time );
1262 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX
1263 0 : || slot->vote_txn_cnt==UINT_MAX
1264 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1265 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->total_txn_cnt - slot->vote_txn_cnt - slot->nonvote_failed_txn_cnt );
1266 0 : if( FD_UNLIKELY( slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1267 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed_txn_cnt );
1268 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX
1269 0 : || slot->failed_txn_cnt==UINT_MAX
1270 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1271 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_txn_cnt - (slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt) );
1272 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX
1273 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1274 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt );
1275 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1276 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1277 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1278 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1279 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
1280 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
1281 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1282 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
1283 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1284 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
1285 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1286 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
1287 0 : jsonp_close_object( gui->http );
1288 :
1289 0 : jsonp_close_object( gui->http );
1290 0 : jsonp_close_envelope( gui->http );
1291 0 : }
1292 :
1293 : void
1294 : fd_gui_printf_slot_transactions_request( fd_gui_t * gui,
1295 : ulong _slot,
1296 0 : ulong id ) {
1297 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
1298 :
1299 0 : char const * level;
1300 0 : switch( slot->level ) {
1301 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1302 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1303 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1304 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1305 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1306 0 : default: level = "unknown"; break;
1307 0 : }
1308 :
1309 0 : fd_gui_slot_t * parent_slot = fd_gui_get_slot( gui, slot->parent_slot );
1310 0 : long duration_nanos = LONG_MAX;
1311 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1312 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1313 0 : }
1314 :
1315 0 : jsonp_open_envelope( gui->http, "slot", "query" );
1316 0 : jsonp_ulong( gui->http, "id", id );
1317 0 : jsonp_open_object( gui->http, "value" );
1318 :
1319 0 : jsonp_open_object( gui->http, "publish" );
1320 0 : jsonp_ulong( gui->http, "slot", _slot );
1321 0 : jsonp_bool( gui->http, "mine", slot->mine );
1322 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1323 0 : jsonp_string( gui->http, "level", level );
1324 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1325 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1326 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1327 0 : else jsonp_long( gui->http, "completed_time_nanos", slot->completed_time );
1328 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX
1329 0 : || slot->vote_txn_cnt==UINT_MAX
1330 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1331 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->total_txn_cnt - slot->vote_txn_cnt - slot->nonvote_failed_txn_cnt );
1332 0 : if( FD_UNLIKELY( slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1333 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed_txn_cnt );
1334 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX
1335 0 : || slot->failed_txn_cnt==UINT_MAX
1336 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1337 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_txn_cnt - (slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt) );
1338 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX
1339 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1340 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt );
1341 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1342 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1343 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1344 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1345 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
1346 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
1347 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1348 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
1349 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1350 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
1351 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1352 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
1353 0 : jsonp_close_object( gui->http );
1354 :
1355 0 : fd_gui_leader_slot_t * lslot = fd_gui_get_leader_slot( gui, _slot );
1356 0 : int overwritten = (gui->pack_txn_idx - lslot->txs.start_offset)>FD_GUI_TXN_HISTORY_SZ;
1357 0 : int processed_all_microblocks = lslot &&
1358 0 : lslot->txs.microblocks_upper_bound!=USHORT_MAX &&
1359 0 : lslot->txs.begin_microblocks==lslot->txs.end_microblocks &&
1360 0 : lslot->txs.begin_microblocks==lslot->txs.microblocks_upper_bound;
1361 :
1362 0 : if( FD_LIKELY( !overwritten && processed_all_microblocks ) ) {
1363 0 : ulong txn_cnt = lslot->txs.end_offset-lslot->txs.start_offset;
1364 :
1365 0 : jsonp_open_object( gui->http, "transactions" );
1366 0 : jsonp_long_as_str( gui->http, "start_timestamp_nanos", lslot->leader_start_time );
1367 0 : jsonp_long_as_str( gui->http, "target_end_timestamp_nanos", lslot->leader_start_time );
1368 0 : jsonp_open_array( gui->http, "txn_mb_start_timestamps_nanos" );
1369 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + (long)gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->timestamp_delta_start_nanos );
1370 0 : jsonp_close_array( gui->http );
1371 0 : jsonp_open_array( gui->http, "txn_mb_end_timestamps_nanos" );
1372 : /* clamp end_ts to start_ts + 1 */
1373 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1374 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + fd_long_max( (long)gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->timestamp_delta_end_nanos,
1375 0 : (long)gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->timestamp_delta_start_nanos + 1L ) );
1376 0 : }
1377 0 : jsonp_close_array( gui->http );
1378 0 : jsonp_open_array( gui->http, "txn_compute_units_requested" );
1379 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 );
1380 0 : jsonp_close_array( gui->http );
1381 0 : jsonp_open_array( gui->http, "txn_compute_units_consumed" );
1382 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 );
1383 0 : jsonp_close_array( gui->http );
1384 0 : jsonp_open_array( gui->http, "txn_priority_fee" );
1385 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 );
1386 0 : jsonp_close_array( gui->http );
1387 0 : jsonp_open_array( gui->http, "txn_transaction_fee" );
1388 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 );
1389 0 : jsonp_close_array( gui->http );
1390 0 : jsonp_open_array( gui->http, "txn_error_code" );
1391 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 );
1392 0 : jsonp_close_array( gui->http );
1393 0 : jsonp_open_array( gui->http, "txn_from_bundle" );
1394 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 );
1395 0 : jsonp_close_array( gui->http );
1396 0 : jsonp_open_array( gui->http, "txn_is_simple_vote" );
1397 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 );
1398 0 : jsonp_close_array( gui->http );
1399 0 : jsonp_open_array( gui->http, "txn_bank_idx" );
1400 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 );
1401 0 : jsonp_close_array( gui->http );
1402 0 : jsonp_open_array( gui->http, "txn_preload_end_timestamps_nanos" );
1403 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1404 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
1405 0 : long microblock_duration = (long)txn->timestamp_delta_end_nanos - (long)txn->timestamp_delta_start_nanos;
1406 0 : long timestamp_delta_preload_end = (long)txn->timestamp_delta_start_nanos + (long)((double)txn->txn_preload_end_pct * (double)microblock_duration / (double)UCHAR_MAX);
1407 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + timestamp_delta_preload_end );
1408 0 : }
1409 0 : jsonp_close_array( gui->http );
1410 0 : jsonp_open_array( gui->http, "txn_start_timestamps_nanos" );
1411 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1412 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
1413 0 : long microblock_duration = (long)txn->timestamp_delta_end_nanos - (long)txn->timestamp_delta_start_nanos;
1414 0 : long timestamp_delta_validate_end = (long)txn->timestamp_delta_start_nanos + (long)((double)txn->txn_start_pct * (double)microblock_duration / (double)UCHAR_MAX);
1415 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + timestamp_delta_validate_end );
1416 0 : }
1417 0 : jsonp_close_array( gui->http );
1418 0 : jsonp_open_array( gui->http, "txn_load_end_timestamps_nanos" );
1419 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1420 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
1421 0 : long microblock_duration = (long)txn->timestamp_delta_end_nanos - (long)txn->timestamp_delta_start_nanos;
1422 0 : long timestamp_delta_load_end = (long)txn->timestamp_delta_start_nanos + (long)((double)txn->txn_load_end_pct * (double)microblock_duration / (double)UCHAR_MAX);
1423 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + timestamp_delta_load_end );
1424 0 : }
1425 0 : jsonp_close_array( gui->http );
1426 0 : jsonp_open_array( gui->http, "txn_end_timestamps_nanos" );
1427 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1428 0 : fd_gui_txn_t * txn = gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
1429 0 : long microblock_duration = (long)txn->timestamp_delta_end_nanos - (long)txn->timestamp_delta_start_nanos;
1430 0 : long timestamp_delta_exec_end = (long)txn->timestamp_delta_start_nanos + (long)((double)txn->txn_end_pct * (double)microblock_duration / (double)UCHAR_MAX);
1431 0 : jsonp_long_as_str( gui->http, NULL, lslot->leader_start_time + timestamp_delta_exec_end );
1432 0 : }
1433 0 : jsonp_close_array( gui->http );
1434 0 : jsonp_open_array( gui->http, "txn_arrival_timestamps_nanos" );
1435 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 );
1436 0 : jsonp_close_array( gui->http );
1437 0 : jsonp_open_array( gui->http, "txn_tips" );
1438 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 );
1439 0 : jsonp_close_array( gui->http );
1440 0 : jsonp_open_array( gui->http, "txn_source_ipv4" );
1441 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1442 0 : char addr[ 64 ];
1443 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 ) );
1444 0 : jsonp_string( gui->http, NULL, addr );
1445 0 : }
1446 0 : jsonp_close_array( gui->http );
1447 0 : jsonp_open_array( gui->http, "txn_source_tpu" );
1448 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1449 0 : switch ( gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->source_tpu ) {
1450 0 : case FD_TXN_M_TPU_SOURCE_QUIC: {
1451 0 : jsonp_string( gui->http, NULL, "quic");
1452 0 : break;
1453 0 : }
1454 0 : case FD_TXN_M_TPU_SOURCE_UDP : {
1455 0 : jsonp_string( gui->http, NULL, "udp");
1456 0 : break;
1457 0 : }
1458 0 : case FD_TXN_M_TPU_SOURCE_GOSSIP: {
1459 0 : jsonp_string( gui->http, NULL, "gossip");
1460 0 : break;
1461 0 : }
1462 0 : case FD_TXN_M_TPU_SOURCE_BUNDLE: {
1463 0 : jsonp_string( gui->http, NULL, "bundle");
1464 0 : break;
1465 0 : }
1466 0 : case FD_TXN_M_TPU_SOURCE_SEND : {
1467 0 : jsonp_string( gui->http, NULL, "send");
1468 0 : break;
1469 0 : }
1470 0 : default: FD_LOG_ERR(("unknown tpu"));
1471 0 : }
1472 0 : }
1473 0 : jsonp_close_array( gui->http );
1474 0 : jsonp_open_array( gui->http, "txn_microblock_id" );
1475 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 );
1476 0 : jsonp_close_array( gui->http );
1477 0 : jsonp_open_array( gui->http, "txn_landed" );
1478 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 );
1479 0 : jsonp_close_array( gui->http );
1480 0 : jsonp_open_array( gui->http, "txn_signature" );
1481 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1482 0 : FD_BASE58_ENCODE_64_BYTES( gui->txs[ (lslot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->signature, encoded_signature );
1483 0 : jsonp_string( gui->http, NULL, encoded_signature );
1484 0 : }
1485 0 : jsonp_close_array( gui->http );
1486 0 : jsonp_close_object( gui->http );
1487 0 : } else {
1488 0 : jsonp_null( gui->http, "transactions" );
1489 0 : }
1490 :
1491 0 : jsonp_close_object( gui->http );
1492 0 : jsonp_close_envelope( gui->http );
1493 0 : }
1494 :
1495 : void
1496 : fd_gui_printf_slot_request_detailed( fd_gui_t * gui,
1497 : ulong _slot,
1498 0 : ulong id ) {
1499 0 : fd_gui_slot_t * slot = fd_gui_get_slot( gui, _slot );
1500 :
1501 0 : char const * level;
1502 0 : switch( slot->level ) {
1503 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1504 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1505 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1506 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1507 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1508 0 : default: level = "unknown"; break;
1509 0 : }
1510 :
1511 0 : fd_gui_slot_t * parent_slot = fd_gui_get_slot( gui, slot->parent_slot );
1512 0 : long duration_nanos = LONG_MAX;
1513 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1514 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1515 0 : }
1516 :
1517 0 : jsonp_open_envelope( gui->http, "slot", "query" );
1518 0 : jsonp_ulong( gui->http, "id", id );
1519 0 : jsonp_open_object( gui->http, "value" );
1520 :
1521 0 : jsonp_open_object( gui->http, "publish" );
1522 0 : jsonp_ulong( gui->http, "slot", _slot );
1523 0 : jsonp_bool( gui->http, "mine", slot->mine );
1524 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1525 0 : jsonp_string( gui->http, "level", level );
1526 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1527 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1528 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1529 0 : else jsonp_long( gui->http, "completed_time_nanos", slot->completed_time );
1530 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX
1531 0 : || slot->vote_txn_cnt==UINT_MAX
1532 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1533 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->total_txn_cnt - slot->vote_txn_cnt - slot->nonvote_failed_txn_cnt );
1534 0 : if( FD_UNLIKELY( slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1535 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed_txn_cnt );
1536 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX
1537 0 : || slot->failed_txn_cnt==UINT_MAX
1538 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1539 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_txn_cnt - (slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt) );
1540 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX
1541 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1542 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt );
1543 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1544 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1545 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1546 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1547 0 : if( FD_UNLIKELY( slot->shred_cnt==UINT_MAX ) ) jsonp_null( gui->http, "shreds" );
1548 0 : else jsonp_ulong( gui->http, "shreds", slot->shred_cnt );
1549 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1550 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
1551 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1552 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
1553 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1554 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
1555 0 : jsonp_close_object( gui->http );
1556 :
1557 0 : if( FD_LIKELY( gui->summary.slot_completed!=ULONG_MAX && gui->summary.slot_completed>_slot ) ) {
1558 0 : fd_gui_printf_waterfall( gui, slot->waterfall_begin, slot->waterfall_end );
1559 :
1560 0 : fd_gui_leader_slot_t * lslot = fd_gui_get_leader_slot( gui, _slot );
1561 0 : if( FD_LIKELY( lslot ) ) {
1562 0 : jsonp_open_array( gui->http, "tile_timers" );
1563 0 : fd_gui_tile_timers_t const * prev_timer = lslot->tile_timers[ 0 ];
1564 0 : for( ulong i=1UL; i<lslot->tile_timers_sample_cnt; i++ ) {
1565 0 : fd_gui_tile_timers_t const * cur_timer = lslot->tile_timers[ i ];
1566 0 : fd_gui_printf_ts_tile_timers( gui, prev_timer, cur_timer );
1567 0 : prev_timer = cur_timer;
1568 0 : }
1569 0 : jsonp_close_array( gui->http );
1570 0 : } else {
1571 : /* Our tile timers were overwritten. */
1572 0 : jsonp_null( gui->http, "tile_timers" );
1573 0 : }
1574 :
1575 0 : fd_gui_printf_tile_stats( gui, slot->tile_stats_begin, slot->tile_stats_end );
1576 0 : } else {
1577 0 : jsonp_null( gui->http, "waterfall" );
1578 0 : jsonp_null( gui->http, "tile_timers" );
1579 0 : jsonp_null( gui->http, "tile_primary_metric" );
1580 0 : }
1581 :
1582 0 : jsonp_close_object( gui->http );
1583 0 : jsonp_close_envelope( gui->http );
1584 0 : }
1585 :
1586 : void
1587 0 : fd_gui_printf_boot_progress( fd_gui_t * gui ) {
1588 0 : jsonp_open_envelope( gui->http, "summary", "boot_progress" );
1589 0 : jsonp_open_object( gui->http, "value" );
1590 0 : switch( gui->summary.boot_progress.phase ) {
1591 0 : case FD_GUI_BOOT_PROGRESS_TYPE_JOINING_GOSSIP: jsonp_string( gui->http, "phase", "joining_gossip" ); break;
1592 0 : case FD_GUI_BOOT_PROGRESS_TYPE_LOADING_FULL_SNAPSHOT: jsonp_string( gui->http, "phase", "loading_full_snapshot" ); break;
1593 0 : case FD_GUI_BOOT_PROGRESS_TYPE_LOADING_INCREMENTAL_SNAPSHOT: jsonp_string( gui->http, "phase", "loading_incremental_snapshot" ); break;
1594 0 : case FD_GUI_BOOT_PROGRESS_TYPE_CATCHING_UP: jsonp_string( gui->http, "phase", "catching_up" ); break;
1595 0 : case FD_GUI_BOOT_PROGRESS_TYPE_RUNNING: jsonp_string( gui->http, "phase", "running" ); break;
1596 0 : default: FD_LOG_ERR(( "unknown phase %d", gui->summary.startup_progress.phase ));
1597 0 : }
1598 :
1599 0 : jsonp_double( gui->http, "joining_gossip_elapsed_seconds", (double)(gui->summary.boot_progress.joining_gossip_time_nanos - gui->summary.startup_time_nanos) / 1e9 );
1600 :
1601 0 : #define HANDLE_SNAPSHOT_STATE(snapshot_type, snapshot_type_upper) \
1602 0 : if( FD_LIKELY( gui->summary.boot_progress.phase>=FD_GUI_BOOT_PROGRESS_TYPE_LOADING_##snapshot_type_upper##_SNAPSHOT )) { \
1603 0 : ulong snapshot_idx = FD_GUI_BOOT_PROGRESS_##snapshot_type_upper##_SNAPSHOT_IDX; \
1604 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 ); \
1605 0 : jsonp_ulong ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_reset_count", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].reset_cnt ); \
1606 0 : jsonp_ulong ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_slot", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].slot ); \
1607 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 ); \
1608 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 ); \
1609 0 : jsonp_string ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_read_path", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].read_path ); \
1610 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 ); \
1611 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 ); \
1612 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 ); \
1613 0 : jsonp_ulong ( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_insert_accounts", gui->summary.boot_progress.loading_snapshot[ snapshot_idx ].insert_accounts_current ); \
1614 0 : } else { \
1615 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_elapsed_seconds" ); \
1616 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_reset_count" ); \
1617 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_slot" ); \
1618 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_total_bytes_compressed" ); \
1619 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_read_bytes_compressed" ); \
1620 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_read_path" ); \
1621 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_decompress_bytes_decompressed" ); \
1622 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_decompress_bytes_compressed" ); \
1623 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_insert_bytes_decompressed" ); \
1624 0 : jsonp_null( gui->http, "loading_" FD_STRINGIFY(snapshot_type) "_snapshot_insert_accounts" ); \
1625 0 : }
1626 :
1627 0 : HANDLE_SNAPSHOT_STATE(full, FULL)
1628 0 : HANDLE_SNAPSHOT_STATE(incremental, INCREMENTAL)
1629 0 : #undef HANDLE_SNAPSHOT_STATE
1630 :
1631 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 );
1632 0 : else jsonp_null( gui->http, "catching_up_elapsed_seconds" );
1633 :
1634 0 : jsonp_close_object( gui->http );
1635 0 : jsonp_close_envelope( gui->http );
1636 0 : }
1637 :
1638 : void
1639 : fd_gui_printf_peers_viewport_update( fd_gui_peers_ctx_t * peers,
1640 0 : ulong ws_conn_id ) {
1641 0 : jsonp_open_envelope( peers->http, "gossip", "view_update" );
1642 0 : jsonp_open_object( peers->http, "value" );
1643 0 : jsonp_open_array( peers->http, "changes" );
1644 :
1645 : /* loop over latest viewport */
1646 0 : FD_TEST( peers->client_viewports[ ws_conn_id ].connected );
1647 0 : if( !(peers->client_viewports[ ws_conn_id ].row_cnt && peers->client_viewports[ ws_conn_id ].row_cnt<FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ) ) FD_LOG_ERR(("row_cnt=%lu", peers->client_viewports[ ws_conn_id ].row_cnt ));
1648 :
1649 0 : for( fd_gui_peers_live_table_fwd_iter_t iter = fd_gui_peers_live_table_fwd_iter_init( peers->live_table, peers->client_viewports[ ws_conn_id ].sort_key, peers->contact_info_table ), j = 0;
1650 0 : !fd_gui_peers_live_table_fwd_iter_done( iter ) && j<peers->client_viewports[ ws_conn_id ].start_row+peers->client_viewports[ ws_conn_id ].row_cnt;
1651 0 : iter = fd_gui_peers_live_table_fwd_iter_next( iter, peers->contact_info_table ), j++ ) {
1652 0 : if( FD_LIKELY( j<peers->client_viewports[ ws_conn_id ].start_row ) ) continue;
1653 0 : fd_gui_peers_node_t const * cur = fd_gui_peers_live_table_fwd_iter_ele_const( iter, peers->contact_info_table );
1654 0 : fd_gui_peers_node_t * ref = &peers->client_viewports[ ws_conn_id ].viewport[ j ];
1655 :
1656 : /* This code should be kept in sync with updates to
1657 : fd_gui_peers_live_table */
1658 0 : if( FD_UNLIKELY( memcmp( cur->contact_info.pubkey.uc, ref->contact_info.pubkey.uc, 32UL ) ) ) {
1659 0 : jsonp_open_object( peers->http, NULL );
1660 0 : jsonp_ulong ( peers->http, "row_index", peers->client_viewports[ ws_conn_id ].start_row + j );
1661 0 : jsonp_string( peers->http, "column_name", "Pubkey" );
1662 :
1663 0 : char pubkey_base58[ FD_BASE58_ENCODED_32_SZ ];
1664 0 : fd_base58_encode_32( cur->contact_info.pubkey.uc, NULL, pubkey_base58 );
1665 0 : jsonp_string( peers->http, "new_value", pubkey_base58 );
1666 0 : jsonp_close_object( peers->http );
1667 0 : }
1668 :
1669 0 : if( FD_UNLIKELY( cur->contact_info.sockets[ FD_CONTACT_INFO_SOCKET_GOSSIP ].addr!=ref->contact_info.sockets[ FD_CONTACT_INFO_SOCKET_GOSSIP ].addr ) ) {
1670 0 : jsonp_open_object( peers->http, NULL );
1671 0 : jsonp_ulong ( peers->http, "row_index", peers->client_viewports[ ws_conn_id ].start_row + j );
1672 0 : jsonp_string( peers->http, "column_name", "IP Addr" );
1673 :
1674 0 : char peer_addr[ 16 ]; /* 255.255.255.255 + '\0' */
1675 0 : FD_TEST( fd_cstr_printf_check( peer_addr, sizeof(peer_addr), NULL, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS(cur->contact_info.sockets[ FD_CONTACT_INFO_SOCKET_GOSSIP ].addr) ) );
1676 0 : jsonp_string( peers->http, "new_value", peer_addr );
1677 0 : jsonp_close_object( peers->http );
1678 0 : }
1679 :
1680 0 : long cur_egress_push_kbps = cur->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate;
1681 0 : long ref_egress_push_kbps = ref->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate;
1682 0 : long cur_ingress_push_kbps = cur->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate;
1683 0 : long ref_ingress_push_kbps = ref->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate;
1684 0 : long cur_egress_pull_response_kbps = cur->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate;
1685 0 : long ref_egress_pull_response_kbps = ref->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate;
1686 0 : long cur_ingress_pull_response_kbps = cur->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate;
1687 0 : long ref_ingress_pull_response_kbps = ref->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate;
1688 :
1689 0 : if( FD_UNLIKELY( ref->valid && cur_ingress_pull_response_kbps!=ref_ingress_pull_response_kbps ) ) {
1690 0 : jsonp_open_object( peers->http, NULL );
1691 0 : jsonp_ulong ( peers->http, "row_index", peers->client_viewports[ ws_conn_id ].start_row + j );
1692 0 : jsonp_string( peers->http, "column_name", "Ingress Pull" );
1693 0 : jsonp_long ( peers->http, "new_value", cur_ingress_pull_response_kbps );
1694 0 : jsonp_close_object( peers->http );
1695 0 : }
1696 :
1697 0 : if( FD_UNLIKELY( ref->valid && cur_ingress_push_kbps!=ref_ingress_push_kbps ) ) {
1698 0 : jsonp_open_object( peers->http, NULL );
1699 0 : jsonp_ulong ( peers->http, "row_index", peers->client_viewports[ ws_conn_id ].start_row + j );
1700 0 : jsonp_string( peers->http, "column_name", "Ingress Push" );
1701 0 : jsonp_long ( peers->http, "new_value", cur_ingress_push_kbps );
1702 0 : jsonp_close_object( peers->http );
1703 0 : }
1704 :
1705 0 : if( FD_UNLIKELY( ref->valid && cur_egress_pull_response_kbps!=ref_egress_pull_response_kbps ) ) {
1706 0 : jsonp_open_object( peers->http, NULL );
1707 0 : jsonp_ulong ( peers->http, "row_index", peers->client_viewports[ ws_conn_id ].start_row + j );
1708 0 : jsonp_string( peers->http, "column_name", "Egress Pull" );
1709 0 : jsonp_long ( peers->http, "new_value", cur_egress_pull_response_kbps );
1710 0 : jsonp_close_object( peers->http );
1711 0 : }
1712 :
1713 0 : if( FD_UNLIKELY( ref->valid && cur_egress_push_kbps!=ref_egress_push_kbps ) ) {
1714 0 : jsonp_open_object( peers->http, NULL );
1715 0 : jsonp_ulong ( peers->http, "row_index", peers->client_viewports[ ws_conn_id ].start_row + j );
1716 0 : jsonp_string( peers->http, "column_name", "Egress Push" );
1717 0 : jsonp_long ( peers->http, "new_value", cur_egress_push_kbps );
1718 0 : jsonp_close_object( peers->http );
1719 0 : }
1720 :
1721 0 : }
1722 0 : jsonp_close_array( peers->http );
1723 0 : jsonp_close_object( peers->http );
1724 0 : jsonp_close_envelope( peers->http );
1725 0 : }
1726 :
1727 : void
1728 : fd_gui_printf_peers_viewport_request( fd_gui_peers_ctx_t * peers,
1729 : char const * key,
1730 : ulong ws_conn_id,
1731 0 : ulong request_id ) {
1732 0 : jsonp_open_envelope( peers->http, "gossip", key );
1733 0 : jsonp_ulong( peers->http, "id", request_id );
1734 0 : jsonp_open_object( peers->http, "value" );
1735 :
1736 0 : FD_TEST( peers->client_viewports[ ws_conn_id ].connected );
1737 0 : if( !(peers->client_viewports[ ws_conn_id ].row_cnt && peers->client_viewports[ ws_conn_id ].row_cnt<FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ) ) FD_LOG_ERR(("row_cnt=%lu", peers->client_viewports[ ws_conn_id ].row_cnt ));
1738 0 : for( fd_gui_peers_live_table_fwd_iter_t iter = fd_gui_peers_live_table_fwd_iter_init( peers->live_table, peers->client_viewports[ ws_conn_id ].sort_key, peers->contact_info_table ), j = 0;
1739 0 : !fd_gui_peers_live_table_fwd_iter_done( iter ) && j<peers->client_viewports[ ws_conn_id ].start_row+peers->client_viewports[ ws_conn_id ].row_cnt;
1740 0 : iter = fd_gui_peers_live_table_fwd_iter_next( iter, peers->contact_info_table ), j++ ) {
1741 0 : if( FD_LIKELY( j<peers->client_viewports[ ws_conn_id ].start_row ) ) continue;
1742 0 : fd_gui_peers_node_t const * cur = fd_gui_peers_live_table_fwd_iter_ele_const( iter, peers->contact_info_table );
1743 :
1744 0 : char row_index_cstr[ 32 ];
1745 0 : FD_TEST( fd_cstr_printf_check( row_index_cstr, sizeof(row_index_cstr), NULL, "%lu", peers->client_viewports[ ws_conn_id ].start_row + j ) );
1746 0 : jsonp_open_object( peers->http, row_index_cstr );
1747 : /* This code should be kept in sync with updates to
1748 : fd_gui_peers_live_table */
1749 :
1750 0 : char pubkey_base58[ FD_BASE58_ENCODED_32_SZ ];
1751 0 : fd_base58_encode_32( cur->contact_info.pubkey.uc, NULL, pubkey_base58 );
1752 0 : jsonp_string( peers->http, "Pubkey", pubkey_base58 );
1753 :
1754 0 : char peer_addr[ 16 ]; /* 255.255.255.255 + '\0' */
1755 0 : FD_TEST( fd_cstr_printf_check( peer_addr, sizeof(peer_addr), NULL, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS(cur->contact_info.sockets[ FD_CONTACT_INFO_SOCKET_GOSSIP ].addr) ) );
1756 0 : jsonp_string( peers->http, "IP Addr", peer_addr );
1757 :
1758 0 : long cur_egress_push_kbps = cur->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate;
1759 0 : long cur_ingress_push_kbps = cur->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate;
1760 0 : long cur_egress_pull_response_kbps = cur->gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate;
1761 0 : long cur_ingress_pull_response_kbps = cur->gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate;
1762 :
1763 0 : jsonp_long ( peers->http, "Ingress Pull", cur_ingress_pull_response_kbps );
1764 0 : jsonp_long ( peers->http, "Ingress Push", cur_ingress_push_kbps );
1765 0 : jsonp_long ( peers->http, "Egress Pull", cur_egress_pull_response_kbps );
1766 0 : jsonp_long ( peers->http, "Egress Push", cur_egress_push_kbps );
1767 :
1768 0 : jsonp_close_object( peers->http );
1769 0 : }
1770 :
1771 0 : jsonp_close_object( peers->http );
1772 0 : jsonp_close_envelope( peers->http );
1773 0 : }
1774 :
1775 : void
1776 0 : fd_gui_printf_peers_view_resize( fd_gui_peers_ctx_t * peers, ulong sz ) {
1777 0 : jsonp_open_envelope( peers->http, "gossip", "peers_size_update" );
1778 0 : jsonp_ulong( peers->http, "value", sz );
1779 0 : jsonp_close_envelope( peers->http );
1780 0 : }
1781 :
1782 : void
1783 0 : fd_gui_peers_printf_gossip_stats( fd_gui_peers_ctx_t * peers ) {
1784 0 : fd_gui_peers_gossip_stats_t * cur = peers->gossip_stats;
1785 :
1786 0 : jsonp_open_envelope( peers->http, "gossip", "network_stats" );
1787 0 : jsonp_open_object( peers->http, "value" );
1788 :
1789 0 : jsonp_open_object( peers->http, "health" );
1790 0 : jsonp_ulong ( peers->http, "num_push_messages_rx_success", cur->network_health_push_msg_rx_success );
1791 0 : jsonp_ulong ( peers->http, "num_push_messages_rx_failure", cur->network_health_push_msg_rx_failure );
1792 0 : jsonp_ulong ( peers->http, "num_push_entries_rx_success", cur->network_health_push_crds_rx_success );
1793 0 : jsonp_ulong ( peers->http, "num_push_entries_rx_failure", cur->network_health_push_crds_rx_failure );
1794 0 : jsonp_ulong ( peers->http, "num_push_entries_rx_duplicate", cur->network_health_push_crds_rx_duplicate );
1795 0 : jsonp_ulong ( peers->http, "num_pull_response_messages_rx_success", cur->network_health_push_msg_rx_success );
1796 0 : jsonp_ulong ( peers->http, "num_pull_response_messages_rx_failure", cur->network_health_pull_response_msg_rx_failure );
1797 0 : jsonp_ulong ( peers->http, "num_pull_response_entries_rx_success", cur->network_health_pull_response_crds_rx_success );
1798 0 : jsonp_ulong ( peers->http, "num_pull_response_entries_rx_failure", cur->network_health_pull_response_crds_rx_failure );
1799 0 : jsonp_ulong ( peers->http, "num_pull_response_entries_rx_duplicate", cur->network_health_pull_response_crds_rx_duplicate );
1800 0 : jsonp_ulong_as_str( peers->http, "total_stake", cur->network_health_total_stake );
1801 0 : jsonp_ulong ( peers->http, "total_peers", cur->network_health_total_peers );
1802 0 : jsonp_ulong_as_str( peers->http, "connected_stake", cur->network_health_connected_stake );
1803 0 : jsonp_ulong ( peers->http, "connected_staked_peers", cur->network_health_connected_staked_peers );
1804 0 : jsonp_ulong ( peers->http, "connected_unstaked_peers", cur->network_health_connected_unstaked_peers );
1805 0 : jsonp_close_object( peers->http );
1806 :
1807 0 : jsonp_open_object( peers->http, "ingress" );
1808 :
1809 0 : jsonp_open_array( peers->http, "peer_names" );
1810 0 : for( ulong i=0UL; i<cur->network_ingress_peer_sz; i++ ) jsonp_string( peers->http, NULL, cur->network_ingress_peer_names[ i ] );
1811 0 : jsonp_close_array( peers->http );
1812 :
1813 0 : jsonp_open_array( peers->http, "peer_identities" );
1814 0 : for( ulong i=0UL; i<cur->network_ingress_peer_sz; i++ ) {
1815 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1816 0 : fd_base58_encode_32( cur->network_ingress_peer_identities[ i ].uc, NULL, identity_base58 );
1817 0 : jsonp_string( peers->http, NULL, identity_base58 );
1818 0 : }
1819 0 : jsonp_close_array( peers->http );
1820 :
1821 0 : jsonp_open_array( peers->http, "peer_throughput" );
1822 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 ] );
1823 0 : jsonp_close_array( peers->http );
1824 0 : jsonp_long( peers->http, "total_throughput", cur->network_ingress_total_bytes_per_sec );
1825 0 : jsonp_close_object( peers->http );
1826 :
1827 0 : jsonp_open_object( peers->http, "egress" );
1828 0 : jsonp_open_array( peers->http, "peer_names" );
1829 0 : for( ulong i=0UL; i<cur->network_egress_peer_sz; i++ ) jsonp_string( peers->http, NULL, cur->network_egress_peer_names[ i ] );
1830 0 : jsonp_close_array( peers->http );
1831 :
1832 0 : jsonp_open_array( peers->http, "peer_identities" );
1833 0 : for( ulong i=0UL; i<cur->network_egress_peer_sz; i++ ) {
1834 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1835 0 : fd_base58_encode_32( cur->network_egress_peer_identities[ i ].uc, NULL, identity_base58 );
1836 0 : jsonp_string( peers->http, NULL, identity_base58 );
1837 0 : }
1838 0 : jsonp_close_array( peers->http );
1839 :
1840 0 : jsonp_open_array( peers->http, "peer_throughput" );
1841 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 ] );
1842 0 : jsonp_close_array( peers->http );
1843 0 : jsonp_long( peers->http, "total_throughput", cur->network_egress_total_bytes_per_sec );
1844 0 : jsonp_close_object( peers->http );
1845 :
1846 0 : jsonp_open_object( peers->http, "storage" );
1847 : /* since these are gauges, we don't take a diff */
1848 0 : jsonp_ulong( peers->http, "capacity", cur->storage_capacity );
1849 0 : jsonp_ulong( peers->http, "expired_count", cur->storage_expired_cnt );
1850 0 : jsonp_ulong( peers->http, "evicted_count", cur->storage_evicted_cnt );
1851 0 : jsonp_open_array( peers->http, "count" );
1852 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_CRDS_VALUE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->storage_active_cnt[ i ] );
1853 0 : jsonp_close_array( peers->http );
1854 0 : jsonp_open_array( peers->http, "count_tx" );
1855 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_CRDS_VALUE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->storage_cnt_tx[ i ] );
1856 0 : jsonp_close_array( peers->http );
1857 0 : jsonp_open_array( peers->http, "bytes_tx" );
1858 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_CRDS_VALUE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->storage_bytes_tx[ i ] );
1859 0 : jsonp_close_array( peers->http );
1860 0 : jsonp_close_object( peers->http );
1861 0 : jsonp_open_object( peers->http, "messages" );
1862 0 : jsonp_open_array( peers->http, "num_bytes_rx" );
1863 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->messages_bytes_rx[ i ] );
1864 0 : jsonp_close_array( peers->http );
1865 0 : jsonp_open_array( peers->http, "num_bytes_tx" );
1866 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->messages_bytes_tx[ i ] );
1867 0 : jsonp_close_array( peers->http );
1868 0 : jsonp_open_array( peers->http, "num_messages_rx" );
1869 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->messages_count_rx[ i ] );
1870 0 : jsonp_close_array( peers->http );
1871 0 : jsonp_open_array( peers->http, "num_messages_tx" );
1872 0 : for( ulong i = 0UL; i<FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT; i++ ) jsonp_ulong( peers->http, NULL, cur->messages_count_tx[ i ] );
1873 0 : jsonp_close_array( peers->http );
1874 0 : jsonp_close_object( peers->http );
1875 0 : jsonp_close_object( peers->http );
1876 0 : jsonp_close_envelope( peers->http );
1877 0 : }
1878 :
1879 : void
1880 0 : fd_gui_printf_shred_updates( fd_gui_t * gui ) {
1881 0 : ulong _start_offset = gui->shreds.staged_next_broadcast;
1882 0 : ulong _end_offset = gui->shreds.staged_tail;
1883 :
1884 0 : ulong min_slot = ULONG_MAX;
1885 0 : long min_ts = LONG_MAX;
1886 :
1887 0 : for( ulong i=_start_offset; i<_end_offset; i++ ) {
1888 0 : min_slot = fd_ulong_min( min_slot, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].slot );
1889 0 : min_ts = fd_long_min ( min_ts, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].timestamp );
1890 0 : }
1891 :
1892 0 : jsonp_open_envelope( gui->http, "slot", "live_shreds" );
1893 0 : jsonp_open_object( gui->http, "value" );
1894 0 : jsonp_ulong ( gui->http, "reference_slot", min_slot );
1895 0 : jsonp_long_as_str( gui->http, "reference_ts", min_ts );
1896 :
1897 0 : jsonp_open_array( gui->http, "slot_delta" );
1898 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 );
1899 0 : jsonp_close_array( gui->http );
1900 0 : jsonp_open_array( gui->http, "shred_idx" );
1901 0 : for( ulong i=_start_offset; i<_end_offset; i++ ) {
1902 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 );
1903 0 : else jsonp_null ( gui->http, NULL );
1904 0 : }
1905 0 : jsonp_close_array( gui->http );
1906 0 : jsonp_open_array( gui->http, "event" );
1907 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 );
1908 0 : jsonp_close_array( gui->http );
1909 0 : jsonp_open_array( gui->http, "event_ts_delta" );
1910 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 );
1911 0 : jsonp_close_array( gui->http );
1912 0 : jsonp_close_object( gui->http );
1913 0 : jsonp_close_envelope( gui->http );
1914 0 : }
1915 :
1916 : void
1917 : fd_gui_printf_slot_shred_updates( fd_gui_t * gui,
1918 : ulong _slot,
1919 0 : ulong id ) {
1920 0 : ulong _start_offset = gui->slots[ _slot % FD_GUI_SLOTS_CNT ]->shreds.start_offset;
1921 0 : ulong _end_offset = gui->slots[ _slot % FD_GUI_SLOTS_CNT ]->shreds.end_offset;
1922 :
1923 0 : ulong min_slot = ULONG_MAX;
1924 0 : long min_ts = LONG_MAX;
1925 :
1926 0 : for( ulong i=_start_offset; i<_end_offset; i++ ) {
1927 0 : min_slot = fd_ulong_min( min_slot, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].slot );
1928 0 : min_ts = fd_long_min ( min_ts, gui->shreds.staged[ i % FD_GUI_SHREDS_STAGING_SZ ].timestamp );
1929 0 : }
1930 :
1931 0 : jsonp_open_envelope( gui->http, "slot", "query_shreds" );
1932 0 : jsonp_ulong( gui->http, "id", id );
1933 0 : jsonp_open_object( gui->http, "value" );
1934 0 : jsonp_ulong ( gui->http, "reference_slot", min_slot );
1935 0 : jsonp_long_as_str( gui->http, "reference_ts", min_ts );
1936 :
1937 0 : jsonp_open_array( gui->http, "slot_delta" );
1938 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 );
1939 0 : jsonp_close_array( gui->http );
1940 0 : jsonp_open_array( gui->http, "shred_idx" );
1941 0 : for( ulong i=_start_offset; i<_end_offset; i++ ) {
1942 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 );
1943 0 : else jsonp_null ( gui->http, NULL );
1944 0 : }
1945 0 : jsonp_close_array( gui->http );
1946 0 : jsonp_open_array( gui->http, "event" );
1947 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 );
1948 0 : jsonp_close_array( gui->http );
1949 0 : jsonp_open_array( gui->http, "event_ts_delta" );
1950 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 );
1951 0 : jsonp_close_array( gui->http );
1952 0 : jsonp_close_object( gui->http );
1953 0 : jsonp_close_envelope( gui->http );
1954 0 : }
|