Line data Source code
1 : #include <ctype.h>
2 : #include <stdio.h>
3 :
4 : #include "fd_gui_printf.h"
5 :
6 : #include "../../waltz/http/fd_http_server_private.h"
7 : #include "../../ballet/utf8/fd_utf8.h"
8 : #include "../../disco/fd_txn_m_t.h"
9 :
10 : #ifdef __has_include
11 : #if __has_include("../../app/fdctl/version.h")
12 : #include "../../app/fdctl/version.h"
13 : #endif
14 : #endif
15 :
16 : #ifndef FDCTL_COMMIT_REF_CSTR
17 : #define FDCTL_COMMIT_REF_CSTR "0000000000000000000000000000000000000000"
18 : #endif
19 :
20 : static void
21 0 : jsonp_strip_trailing_comma( fd_http_server_t * http ) {
22 0 : if( FD_LIKELY( !http->stage_err &&
23 0 : http->stage_len>=1UL &&
24 0 : http->oring[ (http->stage_off%http->oring_sz)+http->stage_len-1UL ]==(uchar)',' ) ) {
25 0 : http->stage_len--;
26 0 : }
27 0 : }
28 :
29 : static void
30 : jsonp_open_object( fd_http_server_t * http,
31 0 : char const * key ) {
32 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":{", key );
33 0 : else fd_http_server_printf( http, "{" );
34 0 : }
35 :
36 : static void
37 0 : jsonp_close_object( fd_http_server_t * http ) {
38 0 : jsonp_strip_trailing_comma( http );
39 0 : fd_http_server_printf( http, "}," );
40 0 : }
41 :
42 : static void
43 : jsonp_open_array( fd_http_server_t * http,
44 0 : char const * key ) {
45 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":[", key );
46 0 : else fd_http_server_printf( http, "[" );
47 0 : }
48 :
49 : static void
50 0 : jsonp_close_array( fd_http_server_t * http ) {
51 0 : jsonp_strip_trailing_comma( http );
52 0 : fd_http_server_printf( http, "]," );
53 0 : }
54 :
55 : static void
56 : jsonp_ulong( fd_http_server_t * http,
57 : char const * key,
58 0 : ulong value ) {
59 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%lu,", key, value );
60 0 : else fd_http_server_printf( http, "%lu,", value );
61 0 : }
62 :
63 : static void
64 : jsonp_long( fd_http_server_t * http,
65 : char const * key,
66 0 : long value ) {
67 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%ld,", key, value );
68 0 : else fd_http_server_printf( http, "%ld,", value );
69 0 : }
70 :
71 : static void
72 : jsonp_double( fd_http_server_t * http,
73 : char const * key,
74 0 : double value ) {
75 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%.2f,", key, value );
76 0 : else fd_http_server_printf( http, "%.2f,", value );
77 0 : }
78 :
79 : static void
80 : jsonp_ulong_as_str( fd_http_server_t * http,
81 : char const * key,
82 0 : ulong value ) {
83 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":\"%lu\",", key, value );
84 0 : else fd_http_server_printf( http, "\"%lu\",", value );
85 0 : }
86 :
87 : static void
88 : jsonp_long_as_str( fd_http_server_t * http,
89 : char const * key,
90 0 : long value ) {
91 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":\"%ld\",", key, value );
92 0 : else fd_http_server_printf( http, "\"%ld\",", value );
93 0 : }
94 :
95 : static void
96 : jsonp_sanitize_str( fd_http_server_t * http,
97 0 : ulong start_len ) {
98 : /* escape quotemark, reverse solidus, and control chars U+0000 through U+001F
99 : just replace with a space */
100 0 : uchar * data = http->oring;
101 0 : for( ulong i=start_len; i<http->stage_len; i++ ) {
102 0 : if( FD_UNLIKELY( data[ (http->stage_off%http->oring_sz)+i ] < 0x20 ||
103 0 : data[ (http->stage_off%http->oring_sz)+i ] == '"' ||
104 0 : data[ (http->stage_off%http->oring_sz)+i ] == '\\' ) ) {
105 0 : data[ (http->stage_off%http->oring_sz)+i ] = ' ';
106 0 : }
107 0 : }
108 0 : }
109 :
110 : static void
111 : jsonp_string( fd_http_server_t * http,
112 : char const * key,
113 0 : char const * value ) {
114 0 : char * val = (void *)value;
115 0 : if( FD_LIKELY( value ) ) {
116 0 : if( FD_UNLIKELY( !fd_utf8_verify( value, strlen( value ) ) )) {
117 0 : val = NULL;
118 0 : }
119 0 : }
120 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":", key );
121 0 : if( FD_LIKELY( val ) ) {
122 0 : fd_http_server_printf( http, "\"" );
123 0 : ulong start_len = http->stage_len;
124 0 : fd_http_server_printf( http, "%s", val );
125 0 : jsonp_sanitize_str( http, start_len );
126 0 : fd_http_server_printf( http, "\"," );
127 0 : } else {
128 0 : fd_http_server_printf( http, "null," );
129 0 : }
130 0 : }
131 :
132 : static void
133 : jsonp_bool( fd_http_server_t * http,
134 : char const * key,
135 0 : int value ) {
136 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\":%s,", key, value ? "true" : "false" );
137 0 : else fd_http_server_printf( http, "%s,", value ? "true" : "false" );
138 0 : }
139 :
140 : static void
141 : jsonp_null( fd_http_server_t * http,
142 0 : char const * key ) {
143 0 : if( FD_LIKELY( key ) ) fd_http_server_printf( http, "\"%s\": null,", key );
144 0 : else fd_http_server_printf( http, "null," );
145 0 : }
146 :
147 : static void
148 : jsonp_open_envelope( fd_http_server_t * http,
149 : char const * topic,
150 0 : char const * key ) {
151 0 : jsonp_open_object( http, NULL );
152 0 : jsonp_string( http, "topic", topic );
153 0 : jsonp_string( http, "key", key );
154 0 : }
155 :
156 : static void
157 0 : jsonp_close_envelope( fd_http_server_t * http ) {
158 0 : jsonp_close_object( http );
159 0 : jsonp_strip_trailing_comma( http );
160 0 : }
161 :
162 : void
163 : fd_gui_printf_open_query_response_envelope( fd_http_server_t * http,
164 : char const * topic,
165 : char const * key,
166 0 : ulong id ) {
167 0 : jsonp_open_object( http, NULL );
168 0 : jsonp_string( http, "topic", topic );
169 0 : jsonp_string( http, "key", key );
170 0 : jsonp_ulong( http, "id", id );
171 0 : }
172 :
173 : void
174 0 : fd_gui_printf_close_query_response_envelope( fd_http_server_t * http ) {
175 0 : jsonp_close_object( http );
176 0 : jsonp_strip_trailing_comma( http );
177 0 : }
178 :
179 : void
180 : fd_gui_printf_null_query_response( fd_http_server_t * http,
181 : char const * topic,
182 : char const * key,
183 0 : ulong id ) {
184 0 : fd_gui_printf_open_query_response_envelope( http, topic, key, id );
185 0 : jsonp_null( http, "value" );
186 0 : fd_gui_printf_close_query_response_envelope( http );
187 0 : }
188 :
189 : void
190 0 : fd_gui_printf_version( fd_gui_t * gui ) {
191 0 : jsonp_open_envelope( gui->http, "summary", "version" );
192 0 : jsonp_string( gui->http, "value", gui->summary.version );
193 0 : jsonp_close_envelope( gui->http );
194 0 : }
195 :
196 : void
197 0 : fd_gui_printf_cluster( fd_gui_t * gui ) {
198 0 : jsonp_open_envelope( gui->http, "summary", "cluster" );
199 0 : jsonp_string( gui->http, "value", gui->summary.cluster );
200 0 : jsonp_close_envelope( gui->http );
201 0 : }
202 :
203 : void
204 0 : fd_gui_printf_commit_hash( fd_gui_t * gui ) {
205 0 : jsonp_open_envelope( gui->http, "summary", "commit_hash" );
206 0 : jsonp_string( gui->http, "value", FDCTL_COMMIT_REF_CSTR );
207 0 : jsonp_close_envelope( gui->http );
208 0 : }
209 :
210 : void
211 0 : fd_gui_printf_identity_key( fd_gui_t * gui ) {
212 0 : jsonp_open_envelope( gui->http, "summary", "identity_key" );
213 0 : jsonp_string( gui->http, "value", gui->summary.identity_key_base58 );
214 0 : jsonp_close_envelope( gui->http );
215 0 : }
216 :
217 : void
218 0 : fd_gui_printf_vote_key( fd_gui_t * gui ) {
219 0 : jsonp_open_envelope( gui->http, "summary", "vote_key" );
220 0 : if( FD_LIKELY( gui->summary.has_vote_key ) ) jsonp_string( gui->http, "value", gui->summary.vote_key_base58 );
221 0 : else jsonp_null( gui->http, "value" );
222 0 : jsonp_close_envelope( gui->http );
223 0 : }
224 :
225 : void
226 0 : fd_gui_printf_startup_time_nanos( fd_gui_t * gui ) {
227 0 : jsonp_open_envelope( gui->http, "summary", "startup_time_nanos" );
228 0 : jsonp_long_as_str( gui->http, "value", gui->summary.startup_time_nanos );
229 0 : jsonp_close_envelope( gui->http );
230 0 : }
231 :
232 : void
233 0 : fd_gui_printf_vote_distance( fd_gui_t * gui ) {
234 0 : jsonp_open_envelope( gui->http, "summary", "vote_distance" );
235 0 : jsonp_ulong( gui->http, "value", gui->summary.vote_distance );
236 0 : jsonp_close_envelope( gui->http );
237 0 : }
238 :
239 :
240 : void
241 0 : fd_gui_printf_vote_state( fd_gui_t * gui ) {
242 0 : jsonp_open_envelope( gui->http, "summary", "vote_state" );
243 0 : switch( gui->summary.vote_state ) {
244 0 : case FD_GUI_VOTE_STATE_NON_VOTING:
245 0 : jsonp_string( gui->http, "value", "non-voting" );
246 0 : break;
247 0 : case FD_GUI_VOTE_STATE_VOTING:
248 0 : jsonp_string( gui->http, "value", "voting" );
249 0 : break;
250 0 : case FD_GUI_VOTE_STATE_DELINQUENT:
251 0 : jsonp_string( gui->http, "value", "delinquent" );
252 0 : break;
253 0 : default:
254 0 : FD_LOG_ERR(( "unknown vote state %d", gui->summary.vote_state ));
255 0 : }
256 0 : jsonp_close_envelope( gui->http );
257 0 : }
258 :
259 : void
260 0 : fd_gui_printf_skipped_history( fd_gui_t * gui ) {
261 0 : jsonp_open_envelope( gui->http, "slot", "skipped_history" );
262 0 : jsonp_open_array( gui->http, "value" );
263 0 : for( ulong i=0UL; i<fd_ulong_min( gui->summary.slot_completed+1, FD_GUI_SLOTS_CNT ); i++ ) {
264 0 : ulong _slot = gui->summary.slot_completed-i;
265 0 : fd_gui_slot_t * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
266 :
267 0 : if( FD_UNLIKELY( slot->slot!=_slot ) ) break;
268 0 : if( FD_UNLIKELY( slot->mine && slot->skipped ) ) jsonp_ulong( gui->http, NULL, slot->slot );
269 0 : }
270 0 : jsonp_close_array( gui->http );
271 0 : jsonp_close_envelope( gui->http );
272 0 : }
273 :
274 : void
275 0 : fd_gui_printf_skipped_history_cluster( fd_gui_t * gui ) {
276 0 : jsonp_open_envelope( gui->http, "slot", "skipped_history_cluster" );
277 0 : jsonp_open_array( gui->http, "value" );
278 0 : for( ulong i=0UL; i<fd_ulong_min( gui->summary.slot_completed+1UL, FD_GUI_SLOTS_CNT ); i++ ) {
279 0 : ulong _slot = gui->summary.slot_completed-i;
280 0 : fd_gui_slot_t * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
281 :
282 0 : if( FD_UNLIKELY( slot->slot!=_slot ) ) break;
283 0 : if( FD_UNLIKELY( slot->skipped ) ) jsonp_ulong( gui->http, NULL, slot->slot );
284 0 : }
285 0 : jsonp_close_array( gui->http );
286 0 : jsonp_close_envelope( gui->http );
287 0 : }
288 :
289 : void
290 0 : fd_gui_printf_tps_history( fd_gui_t * gui ) {
291 0 : jsonp_open_envelope( gui->http, "summary", "tps_history" );
292 0 : jsonp_open_array( gui->http, "value" );
293 :
294 0 : for( ulong i=0UL; i<FD_GUI_TPS_HISTORY_SAMPLE_CNT; i++ ) {
295 0 : ulong idx = (gui->summary.estimated_tps_history_idx+i) % FD_GUI_TPS_HISTORY_SAMPLE_CNT;
296 0 : jsonp_open_array( gui->http, NULL );
297 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ][ 0 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
298 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ][ 1 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
299 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 );
300 0 : jsonp_double( gui->http, NULL, (double)gui->summary.estimated_tps_history[ idx ][ 2 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
301 0 : jsonp_close_array( gui->http );
302 0 : }
303 :
304 0 : jsonp_close_array( gui->http );
305 0 : jsonp_close_envelope( gui->http );
306 0 : }
307 :
308 : void
309 0 : fd_gui_printf_startup_progress( fd_gui_t * gui ) {
310 0 : char const * phase;
311 :
312 0 : switch( gui->summary.startup_progress.phase ) {
313 0 : case FD_GUI_START_PROGRESS_TYPE_INITIALIZING:
314 0 : phase = "initializing";
315 0 : break;
316 0 : case FD_GUI_START_PROGRESS_TYPE_SEARCHING_FOR_FULL_SNAPSHOT:
317 0 : phase = "searching_for_full_snapshot";
318 0 : break;
319 0 : case FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT:
320 0 : phase = "downloading_full_snapshot";
321 0 : break;
322 0 : case FD_GUI_START_PROGRESS_TYPE_SEARCHING_FOR_INCREMENTAL_SNAPSHOT:
323 0 : phase = "searching_for_incremental_snapshot";
324 0 : break;
325 0 : case FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT:
326 0 : phase = "downloading_incremental_snapshot";
327 0 : break;
328 0 : case FD_GUI_START_PROGRESS_TYPE_CLEANING_BLOCK_STORE:
329 0 : phase = "cleaning_blockstore";
330 0 : break;
331 0 : case FD_GUI_START_PROGRESS_TYPE_CLEANING_ACCOUNTS:
332 0 : phase = "cleaning_accounts";
333 0 : break;
334 0 : case FD_GUI_START_PROGRESS_TYPE_LOADING_LEDGER:
335 0 : phase = "loading_ledger";
336 0 : break;
337 0 : case FD_GUI_START_PROGRESS_TYPE_PROCESSING_LEDGER:
338 0 : phase = "processing_ledger";
339 0 : break;
340 0 : case FD_GUI_START_PROGRESS_TYPE_STARTING_SERVICES:
341 0 : phase = "starting_services";
342 0 : break;
343 0 : case FD_GUI_START_PROGRESS_TYPE_HALTED:
344 0 : phase = "halted";
345 0 : break;
346 0 : case FD_GUI_START_PROGRESS_TYPE_WAITING_FOR_SUPERMAJORITY:
347 0 : phase = "waiting_for_supermajority";
348 0 : break;
349 0 : case FD_GUI_START_PROGRESS_TYPE_RUNNING:
350 0 : phase = "running";
351 0 : break;
352 0 : default:
353 0 : FD_LOG_ERR(( "unknown phase %d", gui->summary.startup_progress.phase ));
354 0 : }
355 :
356 0 : jsonp_open_envelope( gui->http, "summary", "startup_progress" );
357 0 : jsonp_open_object( gui->http, "value" );
358 0 : jsonp_string( gui->http, "phase", phase );
359 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_FULL_SNAPSHOT) ) {
360 0 : char peer_addr[ 64 ];
361 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 ) );
362 :
363 0 : jsonp_string( gui->http, "downloading_full_snapshot_peer", peer_addr );
364 0 : jsonp_ulong( gui->http, "downloading_full_snapshot_slot", gui->summary.startup_progress.startup_full_snapshot_slot );
365 0 : jsonp_double( gui->http, "downloading_full_snapshot_elapsed_secs", gui->summary.startup_progress.startup_full_snapshot_elapsed_secs );
366 0 : jsonp_double( gui->http, "downloading_full_snapshot_remaining_secs", gui->summary.startup_progress.startup_full_snapshot_remaining_secs );
367 0 : jsonp_double( gui->http, "downloading_full_snapshot_throughput", gui->summary.startup_progress.startup_full_snapshot_throughput );
368 0 : jsonp_ulong( gui->http, "downloading_full_snapshot_total_bytes", gui->summary.startup_progress.startup_full_snapshot_total_bytes );
369 0 : jsonp_ulong( gui->http, "downloading_full_snapshot_current_bytes", gui->summary.startup_progress.startup_full_snapshot_current_bytes );
370 0 : } else {
371 0 : jsonp_null( gui->http, "downloading_full_snapshot_peer" );
372 0 : jsonp_null( gui->http, "downloading_full_snapshot_slot" );
373 0 : jsonp_null( gui->http, "downloading_full_snapshot_elapsed_secs" );
374 0 : jsonp_null( gui->http, "downloading_full_snapshot_remaining_secs" );
375 0 : jsonp_null( gui->http, "downloading_full_snapshot_throughput" );
376 0 : jsonp_null( gui->http, "downloading_full_snapshot_total_bytes" );
377 0 : jsonp_null( gui->http, "downloading_full_snapshot_current_bytes" );
378 0 : }
379 :
380 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUI_START_PROGRESS_TYPE_DOWNLOADING_INCREMENTAL_SNAPSHOT) ) {
381 0 : char peer_addr[ 64 ];
382 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 ) );
383 :
384 0 : jsonp_string( gui->http, "downloading_incremental_snapshot_peer", peer_addr );
385 0 : jsonp_ulong( gui->http, "downloading_incremental_snapshot_slot", gui->summary.startup_progress.startup_incremental_snapshot_slot );
386 0 : jsonp_double( gui->http, "downloading_incremental_snapshot_elapsed_secs", gui->summary.startup_progress.startup_incremental_snapshot_elapsed_secs );
387 0 : jsonp_double( gui->http, "downloading_incremental_snapshot_remaining_secs", gui->summary.startup_progress.startup_incremental_snapshot_remaining_secs );
388 0 : jsonp_double( gui->http, "downloading_incremental_snapshot_throughput", gui->summary.startup_progress.startup_incremental_snapshot_throughput );
389 0 : jsonp_ulong( gui->http, "downloading_incremental_snapshot_total_bytes", gui->summary.startup_progress.startup_incremental_snapshot_total_bytes );
390 0 : jsonp_ulong( gui->http, "downloading_incremental_snapshot_current_bytes", gui->summary.startup_progress.startup_incremental_snapshot_current_bytes );
391 0 : } else {
392 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_peer" );
393 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_slot" );
394 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_elapsed_secs" );
395 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_remaining_secs" );
396 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_throughput" );
397 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_total_bytes" );
398 0 : jsonp_null( gui->http, "downloading_incremental_snapshot_current_bytes" );
399 0 : }
400 :
401 0 : if( FD_LIKELY( gui->summary.startup_progress.phase>=FD_GUI_START_PROGRESS_TYPE_PROCESSING_LEDGER) ) {
402 0 : jsonp_ulong( gui->http, "ledger_slot", gui->summary.startup_progress.startup_ledger_slot );
403 0 : jsonp_ulong( gui->http, "ledger_max_slot", gui->summary.startup_progress.startup_ledger_max_slot );
404 0 : } else {
405 0 : jsonp_null( gui->http, "ledger_slot" );
406 0 : jsonp_null( gui->http, "ledger_max_slot" );
407 0 : }
408 :
409 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 ) {
410 0 : jsonp_ulong( gui->http, "waiting_for_supermajority_slot", gui->summary.startup_progress.startup_waiting_for_supermajority_slot );
411 0 : jsonp_ulong( gui->http, "waiting_for_supermajority_stake_percent", gui->summary.startup_progress.startup_waiting_for_supermajority_stake_pct );
412 0 : } else {
413 0 : jsonp_null( gui->http, "waiting_for_supermajority_slot" );
414 0 : jsonp_null( gui->http, "waiting_for_supermajority_stake_percent" );
415 0 : }
416 0 : jsonp_close_object( gui->http );
417 0 : jsonp_close_envelope( gui->http );
418 0 : }
419 :
420 : void
421 0 : fd_gui_printf_block_engine( fd_gui_t * gui ) {
422 0 : jsonp_open_envelope( gui->http, "block_engine", "update" );
423 0 : jsonp_open_object( gui->http, "value" );
424 0 : jsonp_string( gui->http, "name", gui->block_engine.name );
425 0 : jsonp_string( gui->http, "url", gui->block_engine.url );
426 0 : jsonp_string( gui->http, "ip", gui->block_engine.ip_cstr );
427 0 : if( FD_LIKELY( gui->block_engine.status==1 ) ) jsonp_string( gui->http, "status", "connecting" );
428 0 : else if( FD_LIKELY( gui->block_engine.status==2 ) ) jsonp_string( gui->http, "status", "connected" );
429 0 : else jsonp_string( gui->http, "status", "disconnected" );
430 0 : jsonp_close_object( gui->http );
431 0 : jsonp_close_envelope( gui->http );
432 0 : }
433 :
434 : void
435 0 : fd_gui_printf_tiles( fd_gui_t * gui ) {
436 0 : jsonp_open_envelope( gui->http, "summary", "tiles" );
437 0 : jsonp_open_array( gui->http, "value" );
438 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
439 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
440 :
441 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
442 : /* bench tiles not reported */
443 0 : continue;
444 0 : }
445 :
446 0 : jsonp_open_object( gui->http, NULL );
447 0 : jsonp_string( gui->http, "kind", tile->name );
448 0 : jsonp_ulong( gui->http, "kind_id", tile->kind_id );
449 0 : jsonp_close_object( gui->http );
450 0 : }
451 0 : jsonp_close_array( gui->http );
452 0 : jsonp_close_envelope( gui->http );
453 0 : }
454 :
455 : void
456 0 : fd_gui_printf_schedule_strategy( fd_gui_t * gui ) {
457 0 : jsonp_open_envelope( gui->http, "summary", "schedule_strategy" );
458 0 : char mode[10];
459 0 : switch (gui->summary.schedule_strategy) {
460 0 : case 0: strncpy( mode, "perf", sizeof(mode) ); break;
461 0 : case 1: strncpy( mode, "balanced", sizeof(mode) ); break;
462 0 : case 2: strncpy( mode, "revenue", sizeof(mode) ); break;
463 0 : default: FD_LOG_ERR(("unexpected schedule_strategy %d", gui->summary.schedule_strategy));
464 0 : }
465 0 : mode[ sizeof(mode) - 1] = '\0';
466 0 : jsonp_string( gui->http, "value", mode );
467 0 : jsonp_close_envelope( gui->http );
468 0 : }
469 :
470 : void
471 0 : fd_gui_printf_identity_balance( fd_gui_t * gui ) {
472 0 : jsonp_open_envelope( gui->http, "summary", "identity_balance" );
473 0 : jsonp_ulong_as_str( gui->http, "value", gui->summary.identity_account_balance );
474 0 : jsonp_close_envelope( gui->http );
475 0 : }
476 :
477 : void
478 0 : fd_gui_printf_vote_balance( fd_gui_t * gui ) {
479 0 : jsonp_open_envelope( gui->http, "summary", "vote_balance" );
480 0 : jsonp_ulong_as_str( gui->http, "value", gui->summary.vote_account_balance );
481 0 : jsonp_close_envelope( gui->http );
482 0 : }
483 :
484 : void
485 0 : fd_gui_printf_estimated_slot_duration_nanos( fd_gui_t * gui ) {
486 0 : jsonp_open_envelope( gui->http, "summary", "estimated_slot_duration_nanos" );
487 0 : jsonp_ulong( gui->http, "value", gui->summary.estimated_slot_duration_nanos );
488 0 : jsonp_close_envelope( gui->http );
489 0 : }
490 :
491 :
492 : void
493 0 : fd_gui_printf_root_slot( fd_gui_t * gui ) {
494 0 : jsonp_open_envelope( gui->http, "summary", "root_slot" );
495 0 : jsonp_ulong( gui->http, "value", gui->summary.slot_rooted );
496 0 : jsonp_close_envelope( gui->http );
497 0 : }
498 :
499 : void
500 0 : fd_gui_printf_optimistically_confirmed_slot( fd_gui_t * gui ) {
501 0 : jsonp_open_envelope( gui->http, "summary", "optimistically_confirmed_slot" );
502 0 : jsonp_ulong( gui->http, "value", gui->summary.slot_optimistically_confirmed );
503 0 : jsonp_close_envelope( gui->http );
504 0 : }
505 :
506 : void
507 0 : fd_gui_printf_completed_slot( fd_gui_t * gui ) {
508 0 : jsonp_open_envelope( gui->http, "summary", "completed_slot" );
509 0 : jsonp_ulong( gui->http, "value", gui->summary.slot_completed );
510 0 : jsonp_close_envelope( gui->http );
511 0 : }
512 :
513 : void
514 0 : fd_gui_printf_estimated_slot( fd_gui_t * gui ) {
515 0 : jsonp_open_envelope( gui->http, "summary", "estimated_slot" );
516 0 : jsonp_ulong( gui->http, "value", gui->summary.slot_estimated );
517 0 : jsonp_close_envelope( gui->http );
518 0 : }
519 :
520 : void
521 : fd_gui_printf_skip_rate( fd_gui_t * gui,
522 0 : ulong epoch_idx ) {
523 0 : jsonp_open_envelope( gui->http, "summary", "skip_rate" );
524 0 : jsonp_open_object( gui->http, "value" );
525 0 : jsonp_ulong( gui->http, "epoch", gui->epoch.epochs[ epoch_idx ].epoch );
526 0 : if( FD_UNLIKELY( !gui->epoch.epochs[ epoch_idx ].my_total_slots ) ) jsonp_double( gui->http, "skip_rate", 0.0 );
527 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 );
528 0 : jsonp_close_object( gui->http );
529 0 : jsonp_close_envelope( gui->http );
530 0 : }
531 :
532 : void
533 : fd_gui_printf_epoch( fd_gui_t * gui,
534 0 : ulong epoch_idx ) {
535 0 : jsonp_open_envelope( gui->http, "epoch", "new" );
536 0 : jsonp_open_object( gui->http, "value" );
537 0 : jsonp_ulong( gui->http, "epoch", gui->epoch.epochs[ epoch_idx ].epoch );
538 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 );
539 0 : else jsonp_null( gui->http, "start_time_nanos" );
540 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 );
541 0 : else jsonp_null( gui->http, "end_time_nanos" );
542 0 : jsonp_ulong( gui->http, "start_slot", gui->epoch.epochs[ epoch_idx ].start_slot );
543 0 : jsonp_ulong( gui->http, "end_slot", gui->epoch.epochs[ epoch_idx ].end_slot );
544 0 : jsonp_ulong_as_str( gui->http, "excluded_stake_lamports", gui->epoch.epochs[ epoch_idx ].excluded_stake );
545 0 : jsonp_open_array( gui->http, "staked_pubkeys" );
546 0 : fd_epoch_leaders_t * lsched = gui->epoch.epochs[epoch_idx].lsched;
547 0 : for( ulong i=0UL; i<lsched->pub_cnt; i++ ) {
548 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
549 0 : fd_base58_encode_32( lsched->pub[ i ].uc, NULL, identity_base58 );
550 0 : jsonp_string( gui->http, NULL, identity_base58 );
551 0 : }
552 0 : jsonp_close_array( gui->http );
553 :
554 0 : jsonp_open_array( gui->http, "staked_lamports" );
555 0 : fd_vote_stake_weight_t * stakes = gui->epoch.epochs[epoch_idx].stakes;
556 0 : for( ulong i=0UL; i<lsched->pub_cnt; i++ ) jsonp_ulong_as_str( gui->http, NULL, stakes[ i ].stake );
557 0 : jsonp_close_array( gui->http );
558 :
559 0 : jsonp_open_array( gui->http, "leader_slots" );
560 0 : for( ulong i = 0; i < lsched->sched_cnt; i++ ) jsonp_ulong( gui->http, NULL, lsched->sched[ i ] );
561 0 : jsonp_close_array( gui->http );
562 0 : jsonp_close_object( gui->http );
563 0 : jsonp_close_envelope( gui->http );
564 0 : }
565 :
566 : static void
567 : fd_gui_printf_waterfall( fd_gui_t * gui,
568 : fd_gui_txn_waterfall_t const * prev,
569 0 : fd_gui_txn_waterfall_t const * cur ) {
570 0 : jsonp_open_object( gui->http, "waterfall" );
571 0 : jsonp_open_object( gui->http, "in" );
572 0 : jsonp_ulong( gui->http, "pack_cranked", cur->in.pack_cranked - prev->in.pack_cranked );
573 0 : jsonp_ulong( gui->http, "pack_retained", prev->out.pack_retained );
574 0 : jsonp_ulong( gui->http, "resolv_retained", prev->out.resolv_retained );
575 0 : jsonp_ulong( gui->http, "quic", cur->in.quic - prev->in.quic );
576 0 : jsonp_ulong( gui->http, "udp", cur->in.udp - prev->in.udp );
577 0 : jsonp_ulong( gui->http, "gossip", cur->in.gossip - prev->in.gossip );
578 0 : jsonp_ulong( gui->http, "block_engine", cur->in.block_engine - prev->in.block_engine );
579 0 : jsonp_close_object( gui->http );
580 :
581 0 : jsonp_open_object( gui->http, "out" );
582 0 : jsonp_ulong( gui->http, "net_overrun", cur->out.net_overrun - prev->out.net_overrun );
583 0 : jsonp_ulong( gui->http, "quic_overrun", cur->out.quic_overrun - prev->out.quic_overrun );
584 0 : jsonp_ulong( gui->http, "quic_frag_drop", cur->out.quic_frag_drop - prev->out.quic_frag_drop );
585 0 : jsonp_ulong( gui->http, "quic_abandoned", cur->out.quic_abandoned - prev->out.quic_abandoned );
586 0 : jsonp_ulong( gui->http, "tpu_quic_invalid", cur->out.tpu_quic_invalid - prev->out.tpu_quic_invalid );
587 0 : jsonp_ulong( gui->http, "tpu_udp_invalid", cur->out.tpu_udp_invalid - prev->out.tpu_udp_invalid );
588 0 : jsonp_ulong( gui->http, "verify_overrun", cur->out.verify_overrun - prev->out.verify_overrun );
589 0 : jsonp_ulong( gui->http, "verify_parse", cur->out.verify_parse - prev->out.verify_parse );
590 0 : jsonp_ulong( gui->http, "verify_failed", cur->out.verify_failed - prev->out.verify_failed );
591 0 : jsonp_ulong( gui->http, "verify_duplicate", cur->out.verify_duplicate - prev->out.verify_duplicate );
592 0 : jsonp_ulong( gui->http, "dedup_duplicate", cur->out.dedup_duplicate - prev->out.dedup_duplicate );
593 0 : jsonp_ulong( gui->http, "resolv_lut_failed", cur->out.resolv_lut_failed - prev->out.resolv_lut_failed );
594 0 : jsonp_ulong( gui->http, "resolv_expired", cur->out.resolv_expired - prev->out.resolv_expired );
595 0 : jsonp_ulong( gui->http, "resolv_ancient", cur->out.resolv_ancient - prev->out.resolv_ancient );
596 0 : jsonp_ulong( gui->http, "resolv_no_ledger", cur->out.resolv_no_ledger - prev->out.resolv_no_ledger );
597 0 : jsonp_ulong( gui->http, "resolv_retained", cur->out.resolv_retained );
598 0 : jsonp_ulong( gui->http, "pack_invalid", cur->out.pack_invalid - prev->out.pack_invalid );
599 0 : jsonp_ulong( gui->http, "pack_invalid_bundle", cur->out.pack_invalid_bundle - prev->out.pack_invalid_bundle );
600 0 : jsonp_ulong( gui->http, "pack_expired", cur->out.pack_expired - prev->out.pack_expired );
601 0 : jsonp_ulong( gui->http, "pack_retained", cur->out.pack_retained );
602 0 : jsonp_ulong( gui->http, "pack_wait_full", cur->out.pack_wait_full - prev->out.pack_wait_full );
603 0 : jsonp_ulong( gui->http, "pack_leader_slow", cur->out.pack_leader_slow - prev->out.pack_leader_slow );
604 0 : jsonp_ulong( gui->http, "bank_invalid", cur->out.bank_invalid - prev->out.bank_invalid );
605 0 : jsonp_ulong( gui->http, "block_success", cur->out.block_success - prev->out.block_success );
606 0 : jsonp_ulong( gui->http, "block_fail", cur->out.block_fail - prev->out.block_fail );
607 0 : jsonp_close_object( gui->http );
608 0 : jsonp_close_object( gui->http );
609 0 : }
610 :
611 : void
612 : fd_gui_printf_live_txn_waterfall( fd_gui_t * gui,
613 : fd_gui_txn_waterfall_t const * prev,
614 : fd_gui_txn_waterfall_t const * cur,
615 0 : ulong next_leader_slot ) {
616 0 : jsonp_open_envelope( gui->http, "summary", "live_txn_waterfall" );
617 0 : jsonp_open_object( gui->http, "value" );
618 0 : jsonp_ulong( gui->http, "next_leader_slot", next_leader_slot );
619 0 : fd_gui_printf_waterfall( gui, prev, cur );
620 0 : jsonp_close_object( gui->http );
621 0 : jsonp_close_envelope( gui->http );
622 0 : }
623 :
624 : static void
625 : fd_gui_printf_tile_stats( fd_gui_t * gui,
626 : fd_gui_tile_stats_t const * prev,
627 0 : fd_gui_tile_stats_t const * cur ) {
628 0 : jsonp_open_object( gui->http, "tile_primary_metric" );
629 0 : jsonp_ulong( gui->http, "quic", cur->quic_conn_cnt );
630 0 : jsonp_double( gui->http, "bundle_rtt_smoothed_millis", (double)(cur->bundle_rtt_smoothed_nanos) / 1000000.0 );
631 :
632 0 : fd_histf_t bundle_rx_delay_hist_delta[ 1 ];
633 0 : fd_histf_subtract( &cur->bundle_rx_delay_hist, &prev->bundle_rx_delay_hist, bundle_rx_delay_hist_delta );
634 0 : ulong bundle_rx_delay_nanos_p90 = fd_histf_percentile( bundle_rx_delay_hist_delta, 90U, ULONG_MAX );
635 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 ));
636 :
637 0 : if( FD_LIKELY( cur->sample_time_nanos>prev->sample_time_nanos ) ) {
638 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) ));
639 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) ));
640 0 : } else {
641 0 : jsonp_ulong( gui->http, "net_in", 0 );
642 0 : jsonp_ulong( gui->http, "net_out", 0 );
643 0 : }
644 0 : if( FD_LIKELY( cur->verify_total_cnt>prev->verify_total_cnt ) ) {
645 0 : jsonp_double( gui->http, "verify", (double)(cur->verify_drop_cnt-prev->verify_drop_cnt) / (double)(cur->verify_total_cnt-prev->verify_total_cnt) );
646 0 : } else {
647 0 : jsonp_double( gui->http, "verify", 0.0 );
648 0 : }
649 0 : if( FD_LIKELY( cur->dedup_total_cnt>prev->dedup_total_cnt ) ) {
650 0 : jsonp_double( gui->http, "dedup", (double)(cur->dedup_drop_cnt-prev->dedup_drop_cnt) / (double)(cur->dedup_total_cnt-prev->dedup_total_cnt) );
651 0 : } else {
652 0 : jsonp_double( gui->http, "dedup", 0.0 );
653 0 : }
654 0 : jsonp_ulong( gui->http, "bank", cur->bank_txn_exec_cnt - prev->bank_txn_exec_cnt );
655 0 : jsonp_double( gui->http, "pack", !cur->pack_buffer_capacity ? 1.0 : (double)cur->pack_buffer_cnt/(double)cur->pack_buffer_capacity );
656 0 : jsonp_double( gui->http, "poh", 0.0 );
657 0 : jsonp_double( gui->http, "shred", 0.0 );
658 0 : jsonp_double( gui->http, "store", 0.0 );
659 0 : jsonp_close_object( gui->http );
660 0 : }
661 :
662 : void
663 : fd_gui_printf_live_tile_stats( fd_gui_t * gui,
664 : fd_gui_tile_stats_t const * prev,
665 0 : fd_gui_tile_stats_t const * cur ) {
666 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_primary_metric" );
667 0 : jsonp_open_object( gui->http, "value" );
668 0 : jsonp_ulong( gui->http, "next_leader_slot", 0UL );
669 0 : fd_gui_printf_tile_stats( gui, prev, cur );
670 0 : jsonp_close_object( gui->http );
671 0 : jsonp_close_envelope( gui->http );
672 0 : }
673 :
674 : static void
675 : fd_gui_printf_tile_timers( fd_gui_t * gui,
676 : fd_gui_tile_timers_t const * prev,
677 0 : fd_gui_tile_timers_t const * cur ) {
678 0 : for( ulong i=0UL; i<gui->topo->tile_cnt; i++ ) {
679 0 : fd_topo_tile_t const * tile = &gui->topo->tiles[ i ];
680 :
681 0 : if( FD_UNLIKELY( !strncmp( tile->name, "bench", 5UL ) ) ) {
682 : /* bench tiles not reported */
683 0 : continue;
684 0 : }
685 :
686 0 : double cur_total = (double)(cur[ i ].caughtup_housekeeping_ticks
687 0 : + cur[ i ].processing_housekeeping_ticks
688 0 : + cur[ i ].backpressure_housekeeping_ticks
689 0 : + cur[ i ].caughtup_prefrag_ticks
690 0 : + cur[ i ].processing_prefrag_ticks
691 0 : + cur[ i ].backpressure_prefrag_ticks
692 0 : + cur[ i ].caughtup_postfrag_ticks
693 0 : + cur[ i ].processing_postfrag_ticks);
694 :
695 0 : double prev_total = (double)(prev[ i ].caughtup_housekeeping_ticks
696 0 : + prev[ i ].processing_housekeeping_ticks
697 0 : + prev[ i ].backpressure_housekeeping_ticks
698 0 : + prev[ i ].caughtup_prefrag_ticks
699 0 : + prev[ i ].processing_prefrag_ticks
700 0 : + prev[ i ].backpressure_prefrag_ticks
701 0 : + prev[ i ].caughtup_postfrag_ticks
702 0 : + prev[ i ].processing_postfrag_ticks);
703 :
704 0 : double idle;
705 0 : if( FD_UNLIKELY( cur_total==prev_total ) ) {
706 : /* The tile didn't sample timers since the last sample, unclear what
707 : idleness should be so send -1. NaN would be better but no NaN in
708 : JSON. */
709 0 : idle = -1;
710 0 : } else {
711 0 : idle = (double)(cur[ i ].caughtup_postfrag_ticks - prev[ i ].caughtup_postfrag_ticks) / (cur_total - prev_total);
712 0 : }
713 :
714 0 : jsonp_double( gui->http, NULL, idle );
715 0 : }
716 0 : }
717 :
718 : void
719 0 : fd_gui_printf_live_tile_timers( fd_gui_t * gui ) {
720 0 : jsonp_open_envelope( gui->http, "summary", "live_tile_timers" );
721 0 : jsonp_open_array( gui->http, "value" );
722 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 ];
723 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 ];
724 0 : fd_gui_printf_tile_timers( gui, prev, cur );
725 0 : jsonp_close_array( gui->http );
726 0 : jsonp_close_envelope( gui->http );
727 0 : }
728 :
729 : void
730 0 : fd_gui_printf_estimated_tps( fd_gui_t * gui ) {
731 0 : ulong idx = (gui->summary.estimated_tps_history_idx+FD_GUI_TPS_HISTORY_SAMPLE_CNT-1UL) % FD_GUI_TPS_HISTORY_SAMPLE_CNT;
732 :
733 0 : jsonp_open_envelope( gui->http, "summary", "estimated_tps" );
734 0 : jsonp_open_object( gui->http, "value" );
735 0 : jsonp_double( gui->http, "total", (double)gui->summary.estimated_tps_history[ idx ][ 0 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
736 0 : jsonp_double( gui->http, "vote", (double)gui->summary.estimated_tps_history[ idx ][ 1 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
737 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 );
738 0 : jsonp_double( gui->http, "nonvote_failed", (double)gui->summary.estimated_tps_history[ idx ][ 2 ]/(double)FD_GUI_TPS_HISTORY_WINDOW_DURATION_SECONDS );
739 0 : jsonp_close_object( gui->http );
740 0 : jsonp_close_envelope( gui->http );
741 0 : }
742 :
743 : static int
744 : fd_gui_gossip_contains( fd_gui_t const * gui,
745 0 : uchar const * pubkey ) {
746 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
747 0 : if( FD_UNLIKELY( !memcmp( gui->gossip.peers[ i ].pubkey->uc, pubkey, 32 ) ) ) return 1;
748 0 : }
749 0 : return 0;
750 0 : }
751 :
752 : static int
753 : fd_gui_vote_acct_contains( fd_gui_t const * gui,
754 0 : uchar const * pubkey ) {
755 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
756 0 : if( FD_UNLIKELY( !memcmp( gui->vote_account.vote_accounts[ i ].pubkey, pubkey, 32 ) ) ) return 1;
757 0 : }
758 0 : return 0;
759 0 : }
760 :
761 : static int
762 : fd_gui_validator_info_contains( fd_gui_t const * gui,
763 0 : uchar const * pubkey ) {
764 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
765 0 : if( FD_UNLIKELY( !memcmp( gui->validator_info.info[ i ].pubkey, pubkey, 32 ) ) ) return 1;
766 0 : }
767 0 : return 0;
768 0 : }
769 :
770 : static void
771 : fd_gui_printf_peer( fd_gui_t * gui,
772 0 : uchar const * identity_pubkey ) {
773 0 : ulong gossip_idx = ULONG_MAX;
774 0 : ulong info_idx = ULONG_MAX;
775 0 : ulong vote_idxs[ FD_GUI_MAX_PEER_CNT ] = {0};
776 0 : ulong vote_idx_cnt = 0UL;
777 :
778 0 : for( ulong i=0UL; i<gui->gossip.peer_cnt; i++ ) {
779 0 : if( FD_UNLIKELY( !memcmp( gui->gossip.peers[ i ].pubkey->uc, identity_pubkey, 32 ) ) ) {
780 0 : gossip_idx = i;
781 0 : break;
782 0 : }
783 0 : }
784 :
785 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
786 0 : if( FD_UNLIKELY( !memcmp( gui->validator_info.info[ i ].pubkey, identity_pubkey, 32 ) ) ) {
787 0 : info_idx = i;
788 0 : break;
789 0 : }
790 0 : }
791 :
792 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
793 0 : if( FD_UNLIKELY( !memcmp( gui->vote_account.vote_accounts[ i ].pubkey, identity_pubkey, 32 ) ) ) {
794 0 : vote_idxs[ vote_idx_cnt++ ] = i;
795 0 : }
796 0 : }
797 :
798 0 : jsonp_open_object( gui->http, NULL );
799 :
800 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
801 0 : fd_base58_encode_32( identity_pubkey, NULL, identity_base58 );
802 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
803 :
804 0 : if( FD_UNLIKELY( gossip_idx==ULONG_MAX ) ) {
805 0 : jsonp_string( gui->http, "gossip", NULL );
806 0 : } else {
807 0 : jsonp_open_object( gui->http, "gossip" );
808 :
809 0 : char version[ 32 ];
810 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 ) );
811 0 : jsonp_string( gui->http, "version", version );
812 0 : jsonp_ulong( gui->http, "feature_set", gui->gossip.peers[ gossip_idx ].version.feature_set );
813 0 : jsonp_ulong( gui->http, "wallclock", gui->gossip.peers[ gossip_idx ].wallclock );
814 0 : jsonp_ulong( gui->http, "shred_version", gui->gossip.peers[ gossip_idx ].shred_version );
815 0 : jsonp_open_object( gui->http, "sockets" );
816 0 : for( ulong j=0UL; j<12UL; j++ ) {
817 0 : if( FD_LIKELY( !gui->gossip.peers[ gossip_idx ].sockets[ j ].ipv4 && !gui->gossip.peers[ gossip_idx ].sockets[ j ].port ) ) continue;
818 0 : char const * tag;
819 0 : switch( j ) {
820 0 : case 0: tag = "gossip"; break;
821 0 : case 1: tag = "rpc"; break;
822 0 : case 2: tag = "rpb_pubsub"; break;
823 0 : case 3: tag = "serve_repair"; break;
824 0 : case 4: tag = "serve_repair_quic"; break;
825 0 : case 5: tag = "tpu"; break;
826 0 : case 6: tag = "tpu_quic"; break;
827 0 : case 7: tag = "tvu"; break;
828 0 : case 8: tag = "tvu_quic"; break;
829 0 : case 9: tag = "tpu_forwards"; break;
830 0 : case 10: tag = "tpu_forwards_quic"; break;
831 0 : case 11: tag = "tpu_vote"; break;
832 0 : }
833 0 : char line[ 64 ];
834 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 ) );
835 0 : jsonp_string( gui->http, tag, line );
836 0 : }
837 0 : jsonp_close_object( gui->http );
838 :
839 0 : jsonp_close_object( gui->http );
840 0 : }
841 :
842 0 : jsonp_open_array( gui->http, "vote" );
843 0 : for( ulong i=0UL; i<vote_idx_cnt; i++ ) {
844 0 : jsonp_open_object( gui->http, NULL );
845 0 : char vote_account_base58[ FD_BASE58_ENCODED_32_SZ ];
846 0 : fd_base58_encode_32( gui->vote_account.vote_accounts[ vote_idxs[ i ] ].vote_account->uc, NULL, vote_account_base58 );
847 0 : jsonp_string( gui->http, "vote_account", vote_account_base58 );
848 0 : jsonp_ulong_as_str( gui->http, "activated_stake", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].activated_stake );
849 0 : jsonp_ulong( gui->http, "last_vote", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].last_vote );
850 0 : jsonp_ulong( gui->http, "root_slot", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].root_slot );
851 0 : jsonp_ulong( gui->http, "epoch_credits", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].epoch_credits );
852 0 : jsonp_ulong( gui->http, "commission", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].commission );
853 0 : jsonp_bool( gui->http, "delinquent", gui->vote_account.vote_accounts[ vote_idxs[ i ] ].delinquent );
854 0 : jsonp_close_object( gui->http );
855 0 : }
856 0 : jsonp_close_array( gui->http );
857 :
858 0 : if( FD_UNLIKELY( info_idx==ULONG_MAX ) ) {
859 0 : jsonp_string( gui->http, "info", NULL );
860 0 : } else {
861 0 : jsonp_open_object( gui->http, "info" );
862 0 : jsonp_string( gui->http, "name", gui->validator_info.info[ info_idx ].name );
863 0 : jsonp_string( gui->http, "details", gui->validator_info.info[ info_idx ].details );
864 0 : jsonp_string( gui->http, "website", gui->validator_info.info[ info_idx ].website );
865 0 : jsonp_string( gui->http, "icon_url", gui->validator_info.info[ info_idx ].icon_uri );
866 0 : jsonp_close_object( gui->http );
867 0 : }
868 :
869 0 : jsonp_close_object( gui->http );
870 0 : }
871 :
872 : void
873 : fd_gui_printf_peers_gossip_update( fd_gui_t * gui,
874 : ulong const * updated,
875 : ulong updated_cnt,
876 : fd_pubkey_t const * removed,
877 : ulong removed_cnt,
878 : ulong const * added,
879 0 : ulong added_cnt ) {
880 0 : jsonp_open_envelope( gui->http, "peers", "update" );
881 0 : jsonp_open_object( gui->http, "value" );
882 0 : jsonp_open_array( gui->http, "add" );
883 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
884 0 : int actually_added = !fd_gui_vote_acct_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc ) &&
885 0 : !fd_gui_validator_info_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
886 0 : if( FD_LIKELY( !actually_added ) ) continue;
887 :
888 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
889 0 : }
890 0 : jsonp_close_array( gui->http );
891 :
892 0 : jsonp_open_array( gui->http, "update" );
893 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
894 0 : int actually_added = !fd_gui_vote_acct_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc ) &&
895 0 : !fd_gui_validator_info_contains( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
896 0 : if( FD_LIKELY( actually_added ) ) continue;
897 :
898 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ added[ i ] ].pubkey->uc );
899 0 : }
900 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
901 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ updated[ i ] ].pubkey->uc );
902 0 : }
903 0 : jsonp_close_array( gui->http );
904 :
905 0 : jsonp_open_array( gui->http, "remove" );
906 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
907 0 : int actually_removed = !fd_gui_vote_acct_contains( gui, removed[ i ].uc ) &&
908 0 : !fd_gui_validator_info_contains( gui, removed[ i ].uc );
909 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
910 :
911 0 : jsonp_open_object( gui->http, NULL );
912 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
913 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
914 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
915 0 : jsonp_close_object( gui->http );
916 0 : }
917 0 : jsonp_close_array( gui->http );
918 0 : jsonp_close_object( gui->http );
919 0 : jsonp_close_envelope( gui->http );
920 0 : }
921 :
922 : void
923 : fd_gui_printf_peers_vote_account_update( fd_gui_t * gui,
924 : ulong const * updated,
925 : ulong updated_cnt,
926 : fd_pubkey_t const * removed,
927 : ulong removed_cnt,
928 : ulong const * added,
929 0 : ulong added_cnt ) {
930 0 : jsonp_open_envelope( gui->http, "peers", "update" );
931 0 : jsonp_open_object( gui->http, "value" );
932 0 : jsonp_open_array( gui->http, "add" );
933 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
934 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
935 0 : !fd_gui_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
936 0 : if( FD_LIKELY( !actually_added ) ) continue;
937 :
938 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
939 0 : }
940 0 : jsonp_close_array( gui->http );
941 :
942 0 : jsonp_open_array( gui->http, "update" );
943 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
944 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
945 0 : !fd_gui_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
946 0 : if( FD_LIKELY( actually_added ) ) continue;
947 :
948 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
949 0 : }
950 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
951 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ updated[ i ] ].pubkey->uc );
952 0 : }
953 0 : jsonp_close_array( gui->http );
954 :
955 0 : jsonp_open_array( gui->http, "remove" );
956 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
957 0 : int actually_removed = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc ) &&
958 0 : !fd_gui_validator_info_contains( gui, gui->vote_account.vote_accounts[ added[ i ] ].pubkey->uc );
959 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
960 :
961 0 : jsonp_open_object( gui->http, NULL );
962 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
963 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
964 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
965 0 : jsonp_close_object( gui->http );
966 0 : }
967 0 : jsonp_close_array( gui->http );
968 0 : jsonp_close_object( gui->http );
969 0 : jsonp_close_envelope( gui->http );
970 0 : }
971 :
972 : void
973 : fd_gui_printf_peers_validator_info_update( fd_gui_t * gui,
974 : ulong const * updated,
975 : ulong updated_cnt,
976 : fd_pubkey_t const * removed,
977 : ulong removed_cnt,
978 : ulong const * added,
979 0 : ulong added_cnt ) {
980 0 : jsonp_open_envelope( gui->http, "peers", "update" );
981 0 : jsonp_open_object( gui->http, "value" );
982 0 : jsonp_open_array( gui->http, "add" );
983 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
984 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
985 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
986 0 : if( FD_LIKELY( !actually_added ) ) continue;
987 :
988 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
989 0 : }
990 0 : jsonp_close_array( gui->http );
991 :
992 0 : jsonp_open_array( gui->http, "update" );
993 0 : for( ulong i=0UL; i<added_cnt; i++ ) {
994 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
995 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
996 0 : if( FD_LIKELY( actually_added ) ) continue;
997 :
998 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
999 0 : }
1000 0 : for( ulong i=0UL; i<updated_cnt; i++ ) {
1001 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ updated[ i ] ].pubkey->uc );
1002 0 : }
1003 0 : jsonp_close_array( gui->http );
1004 :
1005 0 : jsonp_open_array( gui->http, "remove" );
1006 0 : for( ulong i=0UL; i<removed_cnt; i++ ) {
1007 0 : int actually_removed = !fd_gui_gossip_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc ) &&
1008 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ added[ i ] ].pubkey->uc );
1009 0 : if( FD_UNLIKELY( !actually_removed ) ) continue;
1010 :
1011 0 : jsonp_open_object( gui->http, NULL );
1012 0 : char identity_base58[ FD_BASE58_ENCODED_32_SZ ];
1013 0 : fd_base58_encode_32( removed[ i ].uc, NULL, identity_base58 );
1014 0 : jsonp_string( gui->http, "identity_pubkey", identity_base58 );
1015 0 : jsonp_close_object( gui->http );
1016 0 : }
1017 0 : jsonp_close_array( gui->http );
1018 0 : jsonp_close_object( gui->http );
1019 0 : jsonp_close_envelope( gui->http );
1020 0 : }
1021 :
1022 : void
1023 0 : fd_gui_printf_peers_all( fd_gui_t * gui ) {
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<gui->gossip.peer_cnt; i++ ) {
1028 0 : fd_gui_printf_peer( gui, gui->gossip.peers[ i ].pubkey->uc );
1029 0 : }
1030 0 : for( ulong i=0UL; i<gui->vote_account.vote_account_cnt; i++ ) {
1031 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->vote_account.vote_accounts[ i ].pubkey->uc );
1032 0 : if( FD_UNLIKELY( actually_added ) ) {
1033 0 : fd_gui_printf_peer( gui, gui->vote_account.vote_accounts[ i ].pubkey->uc );
1034 0 : }
1035 0 : }
1036 0 : for( ulong i=0UL; i<gui->validator_info.info_cnt; i++ ) {
1037 0 : int actually_added = !fd_gui_gossip_contains( gui, gui->validator_info.info[ i ].pubkey->uc ) &&
1038 0 : !fd_gui_vote_acct_contains( gui, gui->validator_info.info[ i ].pubkey->uc );
1039 0 : if( FD_UNLIKELY( actually_added ) ) {
1040 0 : fd_gui_printf_peer( gui, gui->validator_info.info[ i ].pubkey->uc );
1041 0 : }
1042 0 : }
1043 0 : jsonp_close_array( gui->http );
1044 0 : jsonp_close_object( gui->http );
1045 0 : jsonp_close_envelope( gui->http );
1046 0 : }
1047 :
1048 : static void
1049 : fd_gui_printf_ts_tile_timers( fd_gui_t * gui,
1050 : fd_gui_tile_timers_t const * prev,
1051 0 : fd_gui_tile_timers_t const * cur ) {
1052 0 : jsonp_open_object( gui->http, NULL );
1053 0 : jsonp_ulong_as_str( gui->http, "timestamp_nanos", 0 );
1054 0 : jsonp_open_array( gui->http, "tile_timers" );
1055 0 : fd_gui_printf_tile_timers( gui, prev, cur );
1056 0 : jsonp_close_array( gui->http );
1057 0 : jsonp_close_object( gui->http );
1058 0 : }
1059 :
1060 : void
1061 : fd_gui_printf_slot( fd_gui_t * gui,
1062 0 : ulong _slot ) {
1063 0 : fd_gui_slot_t * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
1064 :
1065 0 : char const * level;
1066 0 : switch( slot->level ) {
1067 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1068 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1069 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1070 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1071 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1072 0 : default: level = "unknown"; break;
1073 0 : }
1074 :
1075 0 : fd_gui_slot_t * parent_slot = gui->slots[ slot->parent_slot % FD_GUI_SLOTS_CNT ];
1076 0 : if( FD_UNLIKELY( parent_slot->slot!=slot->parent_slot ) ) parent_slot = NULL;
1077 :
1078 0 : long duration_nanos = LONG_MAX;
1079 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1080 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1081 0 : }
1082 :
1083 0 : jsonp_open_envelope( gui->http, "slot", "update" );
1084 0 : jsonp_open_object( gui->http, "value" );
1085 0 : jsonp_open_object( gui->http, "publish" );
1086 0 : jsonp_ulong( gui->http, "slot", _slot );
1087 0 : jsonp_bool( gui->http, "mine", slot->mine );
1088 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1089 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1090 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1091 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1092 0 : else jsonp_long_as_str( gui->http, "completed_time_nanos", slot->completed_time );
1093 0 : jsonp_string( gui->http, "level", level );
1094 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX
1095 0 : || slot->vote_txn_cnt==UINT_MAX
1096 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1097 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->total_txn_cnt - slot->vote_txn_cnt - slot->nonvote_failed_txn_cnt );
1098 0 : if( FD_UNLIKELY( slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1099 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed_txn_cnt );
1100 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX
1101 0 : || slot->failed_txn_cnt==UINT_MAX
1102 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1103 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_txn_cnt - (slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt) );
1104 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX
1105 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1106 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt );
1107 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1108 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1109 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1110 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1111 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1112 0 : else jsonp_ulong_as_str( gui->http, "transaction_fee", slot->transaction_fee );
1113 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1114 0 : else jsonp_ulong_as_str( gui->http, "priority_fee", slot->priority_fee );
1115 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1116 0 : else jsonp_ulong_as_str( gui->http, "tips", slot->tips );
1117 0 : jsonp_close_object( gui->http );
1118 0 : jsonp_close_object( gui->http );
1119 0 : jsonp_close_envelope( gui->http );
1120 0 : }
1121 :
1122 : void
1123 : fd_gui_printf_summary_ping( fd_gui_t * gui,
1124 0 : ulong id ) {
1125 0 : jsonp_open_envelope( gui->http, "summary", "ping" );
1126 0 : jsonp_ulong( gui->http, "id", id );
1127 0 : jsonp_null( gui->http, "value" );
1128 0 : jsonp_close_envelope( gui->http );
1129 0 : }
1130 :
1131 : void
1132 : fd_gui_printf_slot_rankings_request( fd_gui_t * gui,
1133 : ulong id,
1134 0 : int mine ) {
1135 0 : ulong epoch = ULONG_MAX;
1136 0 : for( ulong i = 0UL; i<2UL; i++ ) {
1137 0 : if( FD_LIKELY( gui->epoch.has_epoch[ i ] ) ) {
1138 : /* the "current" epoch is the smallest */
1139 0 : epoch = fd_ulong_min( epoch, gui->epoch.epochs[ i ].epoch );
1140 0 : }
1141 0 : }
1142 0 : ulong epoch_idx = epoch % 2UL;
1143 :
1144 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 );
1145 :
1146 0 : jsonp_open_envelope( gui->http, "slot", "query_rankings" );
1147 0 : jsonp_ulong( gui->http, "id", id );
1148 0 : jsonp_open_object( gui->http, "value" );
1149 :
1150 0 : #define OUTPUT_RANKING_ARRAY(field) \
1151 0 : jsonp_open_array( gui->http, "slots_" FD_STRINGIFY(field) ); \
1152 0 : for( ulong i = 0UL; i<fd_ulong_if( epoch==ULONG_MAX, 0UL, FD_GUI_SLOT_RANKINGS_SZ ); i++ ) { \
1153 0 : if( FD_UNLIKELY( rankings->field[ i ].slot==ULONG_MAX ) ) break; \
1154 0 : jsonp_ulong( gui->http, NULL, rankings->field[ i ].slot ); \
1155 0 : } \
1156 0 : jsonp_close_array( gui->http ); \
1157 0 : jsonp_open_array( gui->http, "vals_" FD_STRINGIFY(field) ); \
1158 0 : for( ulong i = 0UL; i<fd_ulong_if( epoch==ULONG_MAX, 0UL, FD_GUI_SLOT_RANKINGS_SZ ); i++ ) { \
1159 0 : if( FD_UNLIKELY( rankings->field[ i ].slot==ULONG_MAX ) ) break; \
1160 0 : jsonp_ulong( gui->http, NULL, rankings->field[ i ].value ); \
1161 0 : } \
1162 0 : jsonp_close_array( gui->http )
1163 :
1164 0 : OUTPUT_RANKING_ARRAY( largest_tips );
1165 0 : OUTPUT_RANKING_ARRAY( largest_fees );
1166 0 : OUTPUT_RANKING_ARRAY( largest_rewards );
1167 0 : OUTPUT_RANKING_ARRAY( largest_duration );
1168 0 : OUTPUT_RANKING_ARRAY( largest_compute_units );
1169 0 : OUTPUT_RANKING_ARRAY( largest_skipped );
1170 0 : OUTPUT_RANKING_ARRAY( smallest_tips );
1171 0 : OUTPUT_RANKING_ARRAY( smallest_fees );
1172 0 : OUTPUT_RANKING_ARRAY( smallest_rewards );
1173 0 : OUTPUT_RANKING_ARRAY( smallest_duration );
1174 0 : OUTPUT_RANKING_ARRAY( smallest_compute_units );
1175 0 : OUTPUT_RANKING_ARRAY( smallest_skipped );
1176 :
1177 0 : #undef OUTPUT_RANKING_ARRAY
1178 :
1179 0 : jsonp_close_object( gui->http );
1180 0 : jsonp_close_envelope( gui->http );
1181 0 : }
1182 :
1183 : void
1184 : fd_gui_printf_slot_request( fd_gui_t * gui,
1185 : ulong _slot,
1186 0 : ulong id ) {
1187 0 : fd_gui_slot_t * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
1188 :
1189 0 : char const * level;
1190 0 : switch( slot->level ) {
1191 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1192 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1193 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1194 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1195 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1196 0 : default: level = "unknown"; break;
1197 0 : }
1198 :
1199 0 : fd_gui_slot_t * parent_slot = gui->slots[ slot->parent_slot % FD_GUI_SLOTS_CNT ];
1200 0 : if( FD_UNLIKELY( parent_slot->slot!=slot->parent_slot ) ) parent_slot = NULL;
1201 :
1202 0 : long duration_nanos = LONG_MAX;
1203 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1204 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1205 0 : }
1206 :
1207 0 : jsonp_open_envelope( gui->http, "slot", "query" );
1208 0 : jsonp_ulong( gui->http, "id", id );
1209 0 : jsonp_open_object( gui->http, "value" );
1210 :
1211 0 : jsonp_open_object( gui->http, "publish" );
1212 0 : jsonp_ulong( gui->http, "slot", _slot );
1213 0 : jsonp_bool( gui->http, "mine", slot->mine );
1214 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1215 0 : jsonp_string( gui->http, "level", level );
1216 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1217 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1218 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1219 0 : else jsonp_long( gui->http, "completed_time_nanos", slot->completed_time );
1220 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX
1221 0 : || slot->vote_txn_cnt==UINT_MAX
1222 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1223 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->total_txn_cnt - slot->vote_txn_cnt - slot->nonvote_failed_txn_cnt );
1224 0 : if( FD_UNLIKELY( slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1225 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed_txn_cnt );
1226 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX
1227 0 : || slot->failed_txn_cnt==UINT_MAX
1228 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1229 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_txn_cnt - (slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt) );
1230 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX
1231 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1232 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt );
1233 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1234 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1235 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1236 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1237 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1238 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
1239 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1240 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
1241 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1242 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
1243 0 : jsonp_close_object( gui->http );
1244 :
1245 0 : jsonp_close_object( gui->http );
1246 0 : jsonp_close_envelope( gui->http );
1247 0 : }
1248 :
1249 : void
1250 : fd_gui_printf_slot_transactions_request( fd_gui_t * gui,
1251 : ulong _slot,
1252 0 : ulong id ) {
1253 0 : fd_gui_slot_t * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
1254 :
1255 0 : char const * level;
1256 0 : switch( slot->level ) {
1257 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1258 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1259 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1260 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1261 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1262 0 : default: level = "unknown"; break;
1263 0 : }
1264 :
1265 0 : fd_gui_slot_t * parent_slot = gui->slots[ slot->parent_slot % FD_GUI_SLOTS_CNT ];
1266 0 : if( FD_UNLIKELY( parent_slot->slot!=slot->parent_slot ) ) parent_slot = NULL;
1267 :
1268 0 : long duration_nanos = LONG_MAX;
1269 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1270 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1271 0 : }
1272 :
1273 0 : jsonp_open_envelope( gui->http, "slot", "query" );
1274 0 : jsonp_ulong( gui->http, "id", id );
1275 0 : jsonp_open_object( gui->http, "value" );
1276 :
1277 0 : jsonp_open_object( gui->http, "publish" );
1278 0 : jsonp_ulong( gui->http, "slot", _slot );
1279 0 : jsonp_bool( gui->http, "mine", slot->mine );
1280 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1281 0 : jsonp_string( gui->http, "level", level );
1282 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1283 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1284 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1285 0 : else jsonp_long( gui->http, "completed_time_nanos", slot->completed_time );
1286 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX
1287 0 : || slot->vote_txn_cnt==UINT_MAX
1288 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1289 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->total_txn_cnt - slot->vote_txn_cnt - slot->nonvote_failed_txn_cnt );
1290 0 : if( FD_UNLIKELY( slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1291 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed_txn_cnt );
1292 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX
1293 0 : || slot->failed_txn_cnt==UINT_MAX
1294 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1295 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_txn_cnt - (slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt) );
1296 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX
1297 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1298 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt );
1299 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1300 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1301 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1302 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1303 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1304 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
1305 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1306 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
1307 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1308 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
1309 0 : jsonp_close_object( gui->http );
1310 :
1311 0 : int overwritten = (gui->pack_txn_idx - slot->txs.start_offset)>FD_GUI_TXN_HISTORY_SZ;
1312 0 : int processed_all_microblocks = slot->slot!=ULONG_MAX &&
1313 0 : slot->txs.microblocks_upper_bound!=USHORT_MAX &&
1314 0 : slot->txs.begin_microblocks==slot->txs.end_microblocks &&
1315 0 : slot->txs.begin_microblocks==slot->txs.microblocks_upper_bound;
1316 :
1317 0 : if( FD_LIKELY( !overwritten && processed_all_microblocks ) ) {
1318 0 : ulong txn_cnt = slot->txs.end_offset-slot->txs.start_offset;
1319 :
1320 0 : jsonp_open_object( gui->http, "transactions" );
1321 0 : jsonp_long_as_str( gui->http, "start_timestamp_nanos", slot->txs.leader_start_time );
1322 0 : jsonp_long_as_str( gui->http, "target_end_timestamp_nanos", slot->txs.leader_end_time );
1323 0 : jsonp_open_array( gui->http, "txn_mb_start_timestamps_nanos" );
1324 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_long_as_str( gui->http, NULL, slot->txs.reference_nanos + (long)gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->timestamp_delta_start_nanos );
1325 0 : jsonp_close_array( gui->http );
1326 0 : jsonp_open_array( gui->http, "txn_mb_end_timestamps_nanos" );
1327 : /* clamp end_ts to start_ts + 1 */
1328 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1329 0 : jsonp_long_as_str( gui->http, NULL, slot->txs.reference_nanos + fd_long_max( (long)gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->timestamp_delta_end_nanos,
1330 0 : (long)gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->timestamp_delta_start_nanos + 1L ) );
1331 0 : }
1332 0 : jsonp_close_array( gui->http );
1333 0 : jsonp_open_array( gui->http, "txn_compute_units_requested" );
1334 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->compute_units_requested );
1335 0 : jsonp_close_array( gui->http );
1336 0 : jsonp_open_array( gui->http, "txn_compute_units_consumed" );
1337 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->compute_units_consumed );
1338 0 : jsonp_close_array( gui->http );
1339 0 : jsonp_open_array( gui->http, "txn_priority_fee" );
1340 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong_as_str( gui->http, NULL, gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->priority_fee );
1341 0 : jsonp_close_array( gui->http );
1342 0 : jsonp_open_array( gui->http, "txn_transaction_fee" );
1343 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong_as_str( gui->http, NULL, gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->transaction_fee );
1344 0 : jsonp_close_array( gui->http );
1345 0 : jsonp_open_array( gui->http, "txn_error_code" );
1346 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->error_code );
1347 0 : jsonp_close_array( gui->http );
1348 0 : jsonp_open_array( gui->http, "txn_from_bundle" );
1349 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_bool( gui->http, NULL, gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->flags & FD_GUI_TXN_FLAGS_FROM_BUNDLE );
1350 0 : jsonp_close_array( gui->http );
1351 0 : jsonp_open_array( gui->http, "txn_is_simple_vote" );
1352 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_bool( gui->http, NULL, gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->flags & FD_GUI_TXN_FLAGS_IS_SIMPLE_VOTE );
1353 0 : jsonp_close_array( gui->http );
1354 0 : jsonp_open_array( gui->http, "txn_bank_idx" );
1355 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->bank_idx );
1356 0 : jsonp_close_array( gui->http );
1357 0 : jsonp_open_array( gui->http, "txn_preload_end_timestamps_nanos" );
1358 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1359 0 : fd_gui_txn_t * txn = gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
1360 0 : long microblock_duration = (long)txn->timestamp_delta_end_nanos - (long)txn->timestamp_delta_start_nanos;
1361 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);
1362 0 : jsonp_long_as_str( gui->http, NULL, slot->txs.reference_nanos + timestamp_delta_preload_end );
1363 0 : }
1364 0 : jsonp_close_array( gui->http );
1365 0 : jsonp_open_array( gui->http, "txn_start_timestamps_nanos" );
1366 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1367 0 : fd_gui_txn_t * txn = gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
1368 0 : long microblock_duration = (long)txn->timestamp_delta_end_nanos - (long)txn->timestamp_delta_start_nanos;
1369 0 : long timestamp_delta_validate_end = (long)txn->timestamp_delta_start_nanos + (long)((double)txn->txn_start_pct * (double)microblock_duration / (double)UCHAR_MAX);
1370 0 : jsonp_long_as_str( gui->http, NULL, slot->txs.reference_nanos + timestamp_delta_validate_end );
1371 0 : }
1372 0 : jsonp_close_array( gui->http );
1373 0 : jsonp_open_array( gui->http, "txn_load_end_timestamps_nanos" );
1374 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1375 0 : fd_gui_txn_t * txn = gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
1376 0 : long microblock_duration = (long)txn->timestamp_delta_end_nanos - (long)txn->timestamp_delta_start_nanos;
1377 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);
1378 0 : jsonp_long_as_str( gui->http, NULL, slot->txs.reference_nanos + timestamp_delta_load_end );
1379 0 : }
1380 0 : jsonp_close_array( gui->http );
1381 0 : jsonp_open_array( gui->http, "txn_end_timestamps_nanos" );
1382 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1383 0 : fd_gui_txn_t * txn = gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ];
1384 0 : long microblock_duration = (long)txn->timestamp_delta_end_nanos - (long)txn->timestamp_delta_start_nanos;
1385 0 : long timestamp_delta_exec_end = (long)txn->timestamp_delta_start_nanos + (long)((double)txn->txn_end_pct * (double)microblock_duration / (double)UCHAR_MAX);
1386 0 : jsonp_long_as_str( gui->http, NULL, slot->txs.reference_nanos + timestamp_delta_exec_end );
1387 0 : }
1388 0 : jsonp_close_array( gui->http );
1389 0 : jsonp_open_array( gui->http, "txn_arrival_timestamps_nanos" );
1390 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_long_as_str( gui->http, NULL, gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->timestamp_arrival_nanos );
1391 0 : jsonp_close_array( gui->http );
1392 0 : jsonp_open_array( gui->http, "txn_tips" );
1393 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong_as_str( gui->http, NULL, gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->tips );
1394 0 : jsonp_close_array( gui->http );
1395 0 : jsonp_open_array( gui->http, "txn_source_ipv4" );
1396 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1397 0 : char addr[ 64 ];
1398 0 : fd_cstr_printf_check( addr, sizeof(addr), NULL, FD_IP4_ADDR_FMT, FD_IP4_ADDR_FMT_ARGS( gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->source_ipv4 ) );
1399 0 : jsonp_string( gui->http, NULL, addr );
1400 0 : }
1401 0 : jsonp_close_array( gui->http );
1402 0 : jsonp_open_array( gui->http, "txn_source_tpu" );
1403 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1404 0 : switch ( gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->source_tpu ) {
1405 0 : case FD_TXN_M_TPU_SOURCE_QUIC: {
1406 0 : jsonp_string( gui->http, NULL, "quic");
1407 0 : break;
1408 0 : }
1409 0 : case FD_TXN_M_TPU_SOURCE_UDP : {
1410 0 : jsonp_string( gui->http, NULL, "udp");
1411 0 : break;
1412 0 : }
1413 0 : case FD_TXN_M_TPU_SOURCE_GOSSIP: {
1414 0 : jsonp_string( gui->http, NULL, "gossip");
1415 0 : break;
1416 0 : }
1417 0 : case FD_TXN_M_TPU_SOURCE_BUNDLE: {
1418 0 : jsonp_string( gui->http, NULL, "bundle");
1419 0 : break;
1420 0 : }
1421 0 : case FD_TXN_M_TPU_SOURCE_SEND : {
1422 0 : jsonp_string( gui->http, NULL, "send");
1423 0 : break;
1424 0 : }
1425 0 : default: FD_LOG_ERR(("unknown tpu"));
1426 0 : }
1427 0 : }
1428 0 : jsonp_close_array( gui->http );
1429 0 : jsonp_open_array( gui->http, "txn_microblock_id" );
1430 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_ulong( gui->http, NULL, gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->microblock_idx );
1431 0 : jsonp_close_array( gui->http );
1432 0 : jsonp_open_array( gui->http, "txn_landed" );
1433 0 : for( ulong i=0UL; i<txn_cnt; i++) jsonp_bool( gui->http, NULL, gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->flags & FD_GUI_TXN_FLAGS_LANDED_IN_BLOCK );
1434 0 : jsonp_close_array( gui->http );
1435 0 : jsonp_open_array( gui->http, "txn_signature" );
1436 0 : for( ulong i=0UL; i<txn_cnt; i++) {
1437 0 : FD_BASE58_ENCODE_64_BYTES( gui->txs[ (slot->txs.start_offset + i)%FD_GUI_TXN_HISTORY_SZ ]->signature, encoded_signature );
1438 0 : jsonp_string( gui->http, NULL, encoded_signature );
1439 0 : }
1440 0 : jsonp_close_array( gui->http );
1441 0 : jsonp_close_object( gui->http );
1442 0 : } else {
1443 0 : jsonp_null( gui->http, "compute_units" );
1444 0 : }
1445 :
1446 0 : jsonp_close_object( gui->http );
1447 0 : jsonp_close_envelope( gui->http );
1448 0 : }
1449 :
1450 : void
1451 : fd_gui_printf_slot_request_detailed( fd_gui_t * gui,
1452 : ulong _slot,
1453 0 : ulong id ) {
1454 0 : fd_gui_slot_t * slot = gui->slots[ _slot % FD_GUI_SLOTS_CNT ];
1455 :
1456 0 : char const * level;
1457 0 : switch( slot->level ) {
1458 0 : case FD_GUI_SLOT_LEVEL_INCOMPLETE: level = "incomplete"; break;
1459 0 : case FD_GUI_SLOT_LEVEL_COMPLETED: level = "completed"; break;
1460 0 : case FD_GUI_SLOT_LEVEL_OPTIMISTICALLY_CONFIRMED: level = "optimistically_confirmed"; break;
1461 0 : case FD_GUI_SLOT_LEVEL_ROOTED: level = "rooted"; break;
1462 0 : case FD_GUI_SLOT_LEVEL_FINALIZED: level = "finalized"; break;
1463 0 : default: level = "unknown"; break;
1464 0 : }
1465 :
1466 0 : fd_gui_slot_t * parent_slot = gui->slots[ slot->parent_slot % FD_GUI_SLOTS_CNT ];
1467 0 : if( FD_UNLIKELY( parent_slot->slot!=slot->parent_slot ) ) parent_slot = NULL;
1468 :
1469 0 : long duration_nanos = LONG_MAX;
1470 0 : if( FD_LIKELY( slot->completed_time!=LONG_MAX && parent_slot && parent_slot->completed_time!=LONG_MAX ) ) {
1471 0 : duration_nanos = slot->completed_time - parent_slot->completed_time;
1472 0 : }
1473 :
1474 0 : jsonp_open_envelope( gui->http, "slot", "query" );
1475 0 : jsonp_ulong( gui->http, "id", id );
1476 0 : jsonp_open_object( gui->http, "value" );
1477 :
1478 0 : jsonp_open_object( gui->http, "publish" );
1479 0 : jsonp_ulong( gui->http, "slot", _slot );
1480 0 : jsonp_bool( gui->http, "mine", slot->mine );
1481 0 : jsonp_bool( gui->http, "skipped", slot->skipped );
1482 0 : jsonp_string( gui->http, "level", level );
1483 0 : if( FD_UNLIKELY( duration_nanos==LONG_MAX ) ) jsonp_null( gui->http, "duration_nanos" );
1484 0 : else jsonp_long( gui->http, "duration_nanos", duration_nanos );
1485 0 : if( FD_UNLIKELY( slot->completed_time==LONG_MAX ) ) jsonp_null( gui->http, "completed_time_nanos" );
1486 0 : else jsonp_long( gui->http, "completed_time_nanos", slot->completed_time );
1487 0 : if( FD_UNLIKELY( slot->total_txn_cnt==UINT_MAX
1488 0 : || slot->vote_txn_cnt==UINT_MAX
1489 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_nonvote_transaction_cnt" );
1490 0 : else jsonp_ulong( gui->http, "success_nonvote_transaction_cnt", slot->total_txn_cnt - slot->vote_txn_cnt - slot->nonvote_failed_txn_cnt );
1491 0 : if( FD_UNLIKELY( slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_nonvote_transaction_cnt" );
1492 0 : else jsonp_ulong( gui->http, "failed_nonvote_transaction_cnt", slot->nonvote_failed_txn_cnt );
1493 0 : if( FD_UNLIKELY( slot->vote_txn_cnt==UINT_MAX
1494 0 : || slot->failed_txn_cnt==UINT_MAX
1495 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "success_vote_transaction_cnt" );
1496 0 : else jsonp_ulong( gui->http, "success_vote_transaction_cnt", slot->vote_txn_cnt - (slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt) );
1497 0 : if( FD_UNLIKELY( slot->failed_txn_cnt==UINT_MAX
1498 0 : || slot->nonvote_failed_txn_cnt==UINT_MAX ) ) jsonp_null( gui->http, "failed_vote_transaction_cnt" );
1499 0 : else jsonp_ulong( gui->http, "failed_vote_transaction_cnt", slot->failed_txn_cnt - slot->nonvote_failed_txn_cnt );
1500 0 : if( FD_UNLIKELY( slot->max_compute_units==UINT_MAX ) ) jsonp_null( gui->http, "max_compute_units" );
1501 0 : else jsonp_ulong( gui->http, "max_compute_units", slot->max_compute_units );
1502 0 : if( FD_UNLIKELY( slot->compute_units==UINT_MAX ) ) jsonp_null( gui->http, "compute_units" );
1503 0 : else jsonp_ulong( gui->http, "compute_units", slot->compute_units );
1504 0 : if( FD_UNLIKELY( slot->transaction_fee==ULONG_MAX ) ) jsonp_null( gui->http, "transaction_fee" );
1505 0 : else jsonp_ulong( gui->http, "transaction_fee", slot->transaction_fee );
1506 0 : if( FD_UNLIKELY( slot->priority_fee==ULONG_MAX ) ) jsonp_null( gui->http, "priority_fee" );
1507 0 : else jsonp_ulong( gui->http, "priority_fee", slot->priority_fee );
1508 0 : if( FD_UNLIKELY( slot->tips==ULONG_MAX ) ) jsonp_null( gui->http, "tips" );
1509 0 : else jsonp_ulong( gui->http, "tips", slot->tips );
1510 0 : jsonp_close_object( gui->http );
1511 :
1512 0 : if( FD_LIKELY( slot->leader_state==FD_GUI_SLOT_LEADER_ENDED ) ) {
1513 0 : fd_gui_printf_waterfall( gui, slot->waterfall_begin, slot->waterfall_end );
1514 :
1515 0 : if( FD_LIKELY( gui->summary.tile_timers_leader_history_slot[ slot->tile_timers_history_idx ]==_slot ) ) {
1516 0 : jsonp_open_array( gui->http, "tile_timers" );
1517 0 : fd_gui_tile_timers_t const * prev_timer = gui->summary.tile_timers_leader_history[ slot->tile_timers_history_idx ][ 0 ];
1518 0 : for( ulong i=1UL; i<gui->summary.tile_timers_leader_history_slot_sample_cnt[ slot->tile_timers_history_idx ]; i++ ) {
1519 0 : fd_gui_tile_timers_t const * cur_timer = gui->summary.tile_timers_leader_history[ slot->tile_timers_history_idx ][ i ];
1520 0 : fd_gui_printf_ts_tile_timers( gui, prev_timer, cur_timer );
1521 0 : prev_timer = cur_timer;
1522 0 : }
1523 0 : jsonp_close_array( gui->http );
1524 0 : } else {
1525 : /* Our tile timers were overwritten. */
1526 0 : jsonp_null( gui->http, "tile_timers" );
1527 0 : }
1528 :
1529 0 : fd_gui_printf_tile_stats( gui, slot->tile_stats_begin, slot->tile_stats_end );
1530 0 : } else {
1531 0 : jsonp_null( gui->http, "waterfall" );
1532 0 : jsonp_null( gui->http, "tile_timers" );
1533 0 : jsonp_null( gui->http, "tile_primary_metric" );
1534 0 : }
1535 :
1536 0 : jsonp_close_object( gui->http );
1537 0 : jsonp_close_envelope( gui->http );
1538 0 : }
|