Line data Source code
1 : #ifndef HEADER_fd_src_disco_gui_fd_gui_peers_h
2 : #define HEADER_fd_src_disco_gui_fd_gui_peers_h
3 :
4 : /* fd_gui_peers defines methods that maintain metrics and metadata about
5 : Solana cluster peers that are active on the Gossip network.
6 :
7 : Peer identifiers are added and removed by incoming update messages
8 : from the gossip tile. Additional information about the peer is
9 : obtained from other places and merged into the a large peers table
10 : with live updates.
11 :
12 : fd_gui_peers also defines methods for handling messages from a
13 : WebSocket client. These messages contain peer related information,
14 : including a live view of the peer table with the option to order the
15 : table a custom sort key. */
16 :
17 : #include "fd_gui_config_parse.h"
18 :
19 : #include "../../disco/metrics/generated/fd_metrics_enums.h"
20 : #include "../../flamenco/gossip/fd_gossip_message.h"
21 : #include "../../flamenco/runtime/fd_runtime_const.h"
22 :
23 : #include "../../waltz/http/fd_http_server.h"
24 : #include "../topo/fd_topo.h"
25 :
26 : #if FD_HAS_ZSTD
27 : #define FD_GUI_GEOIP_ZSTD_COMPRESSION_LEVEL 19
28 0 : #define FD_GUI_GEOIP_ZSTD_WINDOW_LOG 23
29 : #define ZSTD_STATIC_LINKING_ONLY
30 : #include <zstd.h>
31 : #endif
32 :
33 : #include <math.h>
34 :
35 : /* Node in an IP geolocation binary trie. The trie is built from a
36 : compressed binary file with the following format:
37 :
38 : GeoIp Binary layout
39 : | country_code_cnt (8 bytes) |
40 : | country_codes (2*country_code_cnt bytes) |
41 : | city_names_cnt (8 bytes) |
42 : | city_names (see below) |
43 : | record_cnt (8 bytes) |
44 : | records (record_cnt*10UL) |
45 :
46 : Record binary layout
47 : | ip (4 bytes) |
48 : | prefix_sz (1 byte) |
49 : | country_code_idx (1 byte) |
50 : | city_name_idx (4 bytes) |
51 :
52 : country_code_cnt: ulong count of country codes (little-endian)
53 : country_codes: Array of 2-byte ASCII country codes, not null-terminated.
54 : city_names_cnt: ulong count of city names (little-endian).
55 : city_names: Concatenation of variable-length, null-terminated city names
56 : record_cnt: ulong count of CIDR IP ranges in records
57 : records: Series of 10-byte records containing:
58 : ip: network ipv4 address (big-endian)
59 : prefix_sz: uchar count of 1 bits (up to 32) in the netmask of the CIDR address
60 : country_code_idx: uchar country code index, into country_codes
61 : city_name_idx: uint city name index, into city_names.
62 :
63 : In the trie, each node represents one bit position in an IP address.
64 : Paths follow 0 (left child) and 1 (right child) bits from the IP's MSB
65 : to LSB. Nodes with has_prefix=1 indicate a match at that prefix
66 : length country_code_idx references the 2-letter country code in the
67 : table. Maximum depth is 32 levels (for IPv4).
68 :
69 : FD_GUI_GEOIP_*_MAX_NODES should be larger than 2*num_records (since
70 : records are stored in the leaves of a binary tree). */
71 :
72 0 : #define FD_GUI_GEOIP_DBIP_MAX_NODES (1UL<<24UL) /* 16M nodes */
73 0 : #define FD_GUI_GEOIP_MAX_CITY_NAME_SZ (80UL)
74 : #define FD_GUI_GEOIP_MAX_CITY_CNT (160000UL)
75 : #define FD_GUI_GEOIP_MAX_COUNTRY_CNT (254UL)
76 :
77 : struct fd_gui_geoip_node {
78 : uchar has_prefix;
79 : uchar country_code_idx;
80 : uint city_name_idx;
81 :
82 : struct fd_gui_geoip_node * left;
83 : struct fd_gui_geoip_node * right;
84 : };
85 :
86 : typedef struct fd_gui_geoip_node fd_gui_geoip_node_t;
87 :
88 : #define FD_GUI_PEERS_NODE_NOP (0)
89 0 : #define FD_GUI_PEERS_NODE_ADD (1)
90 0 : #define FD_GUI_PEERS_NODE_UPDATE (2)
91 0 : #define FD_GUI_PEERS_NODE_DELETE (3)
92 :
93 0 : #define FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT (256UL) /* maximum number of maintained active sort keys */
94 : #define FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ (200UL) /* the maximum number of rows a client can request for a table viewport */
95 0 : #define FD_GUI_PEERS_WS_VIEWPORT_UPDATE_INTERVAL_MILLIS ( 150L)
96 0 : #define FD_GUI_PEERS_METRIC_RATE_UPDATE_INTERVAL_MILLIS ( 150L)
97 0 : #define FD_GUI_PEERS_GOSSIP_STATS_UPDATE_INTERVAL_MILLIS ( 300L)
98 :
99 0 : #define FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT (64UL)
100 :
101 : /* Some table columns are rates of change, which require keeping a
102 : historical value / timestamp. */
103 : struct fd_gui_peers_metric_rate {
104 : ulong cur;
105 : ulong ref;
106 : long rate_ema; /* units per sec. live_table treaps use this field to sort table entries */
107 : long update_timestamp_ns; /* time when cur was last copied over to ref */
108 : };
109 : typedef struct fd_gui_peers_metric_rate fd_gui_peers_metric_rate_t;
110 :
111 0 : #define FD_GUI_PEERS_EMA_HALF_LIFE_NS (3000000000UL)
112 :
113 : static inline long
114 : fd_gui_peers_adaptive_ema( long last_update_time,
115 : long current_time,
116 : long current_value,
117 0 : long value_at_last_update ) {
118 0 : if( FD_UNLIKELY( last_update_time==0) ) return current_value;
119 :
120 0 : long elapsed_time = current_time - last_update_time;
121 0 : if( FD_UNLIKELY( elapsed_time<=0 ) ) return value_at_last_update;
122 :
123 : // Calculate alpha using half-life formula
124 : // alpha = 1 - exp(-ln(2) * elapsed_time / half_life)
125 0 : double decay_factor = 0.69314718055994 * ((double)elapsed_time / (double)FD_GUI_PEERS_EMA_HALF_LIFE_NS);
126 0 : double alpha = 1.0 - exp(-decay_factor);
127 :
128 0 : if( FD_UNLIKELY( alpha>1.0 ) ) alpha = 1.0;
129 0 : if( FD_UNLIKELY( alpha<0.0 ) ) alpha = 0.0;
130 :
131 0 : return (long)(alpha * (double)current_value + (1.0 - alpha) * (double)value_at_last_update);
132 0 : }
133 :
134 : struct fd_gui_peers_voter {
135 : fd_vote_stake_weight_t weight;
136 : ulong vote_slot;
137 : };
138 : typedef struct fd_gui_peers_voter fd_gui_peers_voter_t;
139 :
140 : struct fd_gui_peers_node {
141 : int valid;
142 : long update_time_nanos;
143 : fd_pubkey_t pubkey;
144 : long wallclock_nanos;
145 : fd_gossip_contact_info_t contact_info;
146 : char name[ FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_NAME_SZ + 1UL ];
147 :
148 : fd_gui_peers_metric_rate_t gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
149 : fd_gui_peers_metric_rate_t gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
150 : fd_gui_peers_metric_rate_t gossvf_rx_sum; /* sum of gossvf_rx */
151 : fd_gui_peers_metric_rate_t gossip_tx_sum; /* sum of gossip_tx */
152 :
153 : int has_vote_info;
154 : fd_pubkey_t vote_account;
155 : int delinquent;
156 : ulong stake;
157 :
158 : uchar country_code_idx;
159 : uint city_name_idx;
160 :
161 : struct {
162 : ulong next;
163 : ulong prev;
164 : } pubkey_map;
165 :
166 : struct {
167 : ulong next;
168 : ulong prev;
169 : } sock_map;
170 :
171 : struct {
172 : ulong parent;
173 : ulong left;
174 : ulong right;
175 : ulong prio;
176 : ulong next;
177 : ulong prev;
178 : } treaps_live_table[ FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT ];
179 : struct {
180 : ulong next;
181 : ulong prev;
182 : } dlist_live_table;
183 : ulong sort_keys_live_table;
184 :
185 : struct {
186 : ulong parent;
187 : ulong left;
188 : ulong right;
189 : ulong prio;
190 : ulong next;
191 : ulong prev;
192 : } treaps_bandwidth_tracking[ 2UL ];
193 : struct {
194 : ulong next;
195 : ulong prev;
196 : } dlist_bandwidth_tracking;
197 : ulong sort_keys_bandwidth_tracking;
198 : };
199 : typedef struct fd_gui_peers_node fd_gui_peers_node_t;
200 :
201 : struct fd_gui_peers_gossip_stats {
202 : long sample_time;
203 : ulong network_health_pull_response_msg_rx_success;
204 : ulong network_health_pull_response_msg_rx_failure;
205 : ulong network_health_push_msg_rx_success;
206 : ulong network_health_push_msg_rx_failure;
207 : ulong network_health_push_crds_rx_duplicate;
208 : ulong network_health_pull_response_crds_rx_duplicate;
209 : ulong network_health_push_crds_rx_success;
210 : ulong network_health_push_crds_rx_failure;
211 : ulong network_health_pull_response_crds_rx_success;
212 : ulong network_health_pull_response_crds_rx_failure;
213 : ulong network_health_push_msg_tx;
214 : ulong network_health_pull_response_msg_tx;
215 : ulong network_health_total_stake; /* lamports */
216 : ulong network_health_total_peers;
217 : ulong network_health_connected_stake; /* lamports */
218 : ulong network_health_connected_staked_peers;
219 : ulong network_health_connected_unstaked_peers;
220 : ulong network_ingress_total_bytes;
221 : ulong network_ingress_peer_sz;
222 : long network_ingress_peer_bytes_per_sec [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
223 : char network_ingress_peer_names [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ][ FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_NAME_SZ + 1UL ];
224 : fd_pubkey_t network_ingress_peer_identities[ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
225 : long network_ingress_total_bytes_per_sec;
226 : ulong network_egress_total_bytes;
227 : ulong network_egress_peer_sz;
228 : long network_egress_peer_bytes_per_sec [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
229 : char network_egress_peer_names [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ][ FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_NAME_SZ + 1UL ];
230 : fd_pubkey_t network_egress_peer_identities[ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
231 : long network_egress_total_bytes_per_sec;
232 : ulong storage_capacity;
233 : ulong storage_expired_cnt;
234 : ulong storage_evicted_cnt;
235 : ulong storage_active_cnt[ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
236 : ulong storage_cnt_tx [ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
237 : ulong storage_bytes_tx [ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
238 : ulong messages_push_rx_cnt;
239 : ulong messages_push_tx_cnt;
240 : ulong messages_pull_response_rx_cnt;
241 : ulong messages_pull_response_tx_cnt;
242 : ulong messages_bytes_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
243 : ulong messages_count_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
244 : ulong messages_bytes_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
245 : ulong messages_count_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
246 : };
247 : typedef struct fd_gui_peers_gossip_stats fd_gui_peers_gossip_stats_t;
248 :
249 : #define POOL_NAME fd_gui_peers_node_info_pool
250 0 : #define POOL_T fd_gui_config_parse_info_t
251 0 : #define POOL_NEXT pool.next
252 : #include "../../util/tmpl/fd_pool.c"
253 :
254 : #define MAP_NAME fd_gui_peers_node_info_map
255 : #define MAP_ELE_T fd_gui_config_parse_info_t
256 : #define MAP_KEY_T fd_pubkey_t
257 0 : #define MAP_KEY pubkey
258 0 : #define MAP_IDX_T ulong
259 0 : #define MAP_NEXT map.next
260 0 : #define MAP_PREV map.prev
261 0 : #define MAP_KEY_HASH(k,s) (fd_hash( (s), (k)->uc, sizeof(fd_pubkey_t) ))
262 0 : #define MAP_KEY_EQ(k0,k1) (!memcmp((k0)->uc, (k1)->uc, 32UL))
263 : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
264 : #include "../../util/tmpl/fd_map_chain.c"
265 :
266 : #define MAP_NAME fd_gui_peers_node_pubkey_map
267 0 : #define MAP_ELE_T fd_gui_peers_node_t
268 : #define MAP_KEY_T fd_pubkey_t
269 0 : #define MAP_KEY pubkey
270 0 : #define MAP_IDX_T ulong
271 0 : #define MAP_NEXT pubkey_map.next
272 0 : #define MAP_PREV pubkey_map.prev
273 0 : #define MAP_KEY_HASH(k,s) (fd_hash( (s), (k)->uc, sizeof(fd_pubkey_t) ))
274 0 : #define MAP_KEY_EQ(k0,k1) (!memcmp((k0)->uc, (k1)->uc, 32UL))
275 : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
276 : #include "../../util/tmpl/fd_map_chain.c"
277 :
278 : #define MAP_NAME fd_gui_peers_node_sock_map
279 0 : #define MAP_ELE_T fd_gui_peers_node_t
280 : #define MAP_KEY_T fd_gossip_socket_t
281 0 : #define MAP_KEY contact_info.sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP ]
282 0 : #define MAP_IDX_T ulong
283 0 : #define MAP_NEXT sock_map.next
284 0 : #define MAP_PREV sock_map.prev
285 0 : #define MAP_KEY_HASH(k,s) ( fd_hash( (s), (k), sizeof(uint) + sizeof(ushort) ) )
286 0 : #define MAP_KEY_EQ(k0,k1) ((k0)->is_ipv6==(k1)->is_ipv6 && (k0)->port==(k1)->port && (!((k0)->is_ipv6) ? (k0)->ip4==(k1)->ip4 : !memcmp((k0)->ip6,(k1)->ip6,16UL)) )
287 : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
288 : #define MAP_MULTI 1
289 : #include "../../util/tmpl/fd_map_chain.c"
290 :
291 0 : static int live_table_col_pubkey_lt( void const * a, void const * b ) { return memcmp( ((fd_pubkey_t *)a)->uc, ((fd_pubkey_t *)b)->uc, 32UL ) < 0; }
292 0 : static int live_table_col_long_lt ( void const * a, void const * b ) { return *(long *)a < *(long *)b; }
293 0 : static int live_table_col_uchar_lt ( void const * a, void const * b ) { return *(uchar *)a < *(uchar *)b; }
294 0 : static int live_table_col_ipv4_lt ( void const * a, void const * b ) { return fd_uint_bswap(*(uint *)a) < fd_uint_bswap(*(uint *)b); }
295 0 : static int live_table_col_name_lt ( void const * a, void const * b ) { return memcmp( (char *)a, (char *)b, FD_GUI_CONFIG_PARSE_VALIDATOR_INFO_NAME_SZ + 1UL ) < 0; }
296 0 : static int live_table_col_stake_lt ( void const * a, void const * b ) { return fd_long_if( *(ulong *)a>LONG_MAX, -1L, (long)*(ulong *)a ) < fd_long_if( *(ulong *)b>LONG_MAX, -1L, (long)*(ulong *)b ); }
297 :
298 : #define LIVE_TABLE_NAME fd_gui_peers_live_table
299 0 : #define LIVE_TABLE_TREAP treaps_live_table
300 0 : #define LIVE_TABLE_SORT_KEYS sort_keys_live_table
301 0 : #define LIVE_TABLE_DLIST dlist_live_table
302 0 : #define LIVE_TABLE_COLUMN_CNT (9UL)
303 0 : #define LIVE_TABLE_MAX_SORT_KEY_CNT FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT
304 : #define LIVE_TABLE_ROW_T fd_gui_peers_node_t
305 0 : #define LIVE_TABLE_COLUMNS LIVE_TABLE_COL_ARRAY( \
306 0 : LIVE_TABLE_COL_ENTRY( "Stake", stake, live_table_col_stake_lt ), \
307 0 : LIVE_TABLE_COL_ENTRY( "Pubkey", pubkey, live_table_col_pubkey_lt ), \
308 0 : LIVE_TABLE_COL_ENTRY( "Name", name, live_table_col_name_lt ), \
309 0 : LIVE_TABLE_COL_ENTRY( "Country", country_code_idx, live_table_col_uchar_lt ), \
310 0 : LIVE_TABLE_COL_ENTRY( "IP Addr", contact_info.sockets[ FD_GOSSIP_CONTACT_INFO_SOCKET_GOSSIP ].ip4, live_table_col_ipv4_lt ), \
311 0 : LIVE_TABLE_COL_ENTRY( "Ingress Push", gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema, live_table_col_long_lt ), \
312 0 : LIVE_TABLE_COL_ENTRY( "Ingress Pull", gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema, live_table_col_long_lt ), \
313 0 : LIVE_TABLE_COL_ENTRY( "Egress Push", gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate_ema, live_table_col_long_lt ), \
314 0 : LIVE_TABLE_COL_ENTRY( "Egress Pull", gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate_ema, live_table_col_long_lt ), )
315 : #include "fd_gui_live_table_tmpl.c"
316 :
317 0 : #define FD_GUI_PEERS_LIVE_TABLE_DEFAULT_SORT_KEY ((fd_gui_peers_live_table_sort_key_t){ .col = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, .dir = { -1, -1, -1, -1, -1, -1, -1, -1, -1 } })
318 :
319 : #define LIVE_TABLE_NAME fd_gui_peers_bandwidth_tracking
320 0 : #define LIVE_TABLE_TREAP treaps_bandwidth_tracking
321 0 : #define LIVE_TABLE_SORT_KEYS sort_keys_bandwidth_tracking
322 0 : #define LIVE_TABLE_DLIST dlist_bandwidth_tracking
323 0 : #define LIVE_TABLE_COLUMN_CNT (2UL)
324 0 : #define LIVE_TABLE_MAX_SORT_KEY_CNT (2UL)
325 : #define LIVE_TABLE_ROW_T fd_gui_peers_node_t
326 0 : #define LIVE_TABLE_COLUMNS LIVE_TABLE_COL_ARRAY( \
327 0 : LIVE_TABLE_COL_ENTRY( "Ingress Total", gossvf_rx_sum.rate_ema, live_table_col_long_lt ), \
328 0 : LIVE_TABLE_COL_ENTRY( "Egress Total", gossip_tx_sum.rate_ema, live_table_col_long_lt ) )
329 : #include "fd_gui_live_table_tmpl.c"
330 :
331 0 : #define FD_GUI_PEERS_BW_TRACKING_INGRESS_SORT_KEY ((fd_gui_peers_bandwidth_tracking_sort_key_t){ .col = { 0, 1 }, .dir = { -1, 0 } })
332 0 : #define FD_GUI_PEERS_BW_TRACKING_EGRESS_SORT_KEY ((fd_gui_peers_bandwidth_tracking_sort_key_t){ .col = { 0, 1 }, .dir = { 0, -1 } })
333 :
334 : struct fd_gui_peers_ws_conn {
335 : int connected;
336 : long connected_time;
337 :
338 : ulong start_row;
339 : ulong row_cnt;
340 : fd_gui_peers_node_t viewport[ FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ ];
341 : fd_gui_peers_live_table_sort_key_t sort_key;
342 : };
343 :
344 : typedef struct fd_gui_peers_ws_conn fd_gui_peers_ws_conn_t;
345 :
346 : struct fd_gui_ip_db {
347 : fd_gui_geoip_node_t * nodes;
348 : char country_code[ FD_GUI_GEOIP_MAX_COUNTRY_CNT ][ 3 ]; /* ISO 3166-1 alpha-2 country codes as cstrings */
349 : char city_name[ FD_GUI_GEOIP_MAX_CITY_CNT ][ FD_GUI_GEOIP_MAX_CITY_NAME_SZ ]; /* city_names as cstrings */
350 : };
351 :
352 : typedef struct fd_gui_ip_db fd_gui_ip_db_t;
353 :
354 : struct fd_gui_peers_ctx {
355 : long next_client_nanos; /* ns timestamp when we'll service the next ws client */
356 : long next_metric_rate_update_nanos; /* ns timestamp when we'll next update rate-of-change metrics */
357 : long next_gossip_stats_update_nanos; /* ns timestamp when we'll next broadcast out gossip stats message */
358 :
359 : fd_gui_config_parse_info_t * node_info_pool;
360 : fd_gui_peers_node_info_map_t * node_info_map;
361 : fd_gui_peers_node_pubkey_map_t * node_pubkey_map;
362 : fd_gui_peers_node_sock_map_t * node_sock_map;
363 : fd_gui_peers_live_table_t * live_table;
364 : fd_gui_peers_bandwidth_tracking_t * bw_tracking;
365 :
366 : fd_http_server_t * http;
367 : fd_topo_t * topo;
368 :
369 : ulong max_ws_conn_cnt;
370 : ulong open_ws_conn_cnt;
371 : ulong active_ws_conn_id;
372 : fd_gui_peers_ws_conn_t * client_viewports; /* points to 2D array with max_ws_conn_cnt rows and FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ columns */
373 :
374 : fd_gui_peers_gossip_stats_t gossip_stats [ 1 ];
375 : fd_gui_peers_node_t contact_info_table[ FD_CONTACT_INFO_TABLE_SIZE ];
376 :
377 : ulong slot_voted; /* last vote slot for this validator */
378 :
379 : /* We want the gui to reflect stakes_t_2 since this is what matters
380 : consequentially for delinquency / leader schedule info.
381 :
382 : All arrays are sorted descending by vote pubkey. */
383 : struct {
384 : ulong epoch;
385 :
386 : ulong stakes_cnt;
387 : fd_gui_peers_voter_t stakes[ MAX_STAKED_LEADERS ];
388 : } epochs[ 2 ];
389 :
390 : union {
391 : struct {
392 : int actions[ FD_CONTACT_INFO_TABLE_SIZE ];
393 : ulong idxs [ FD_CONTACT_INFO_TABLE_SIZE ];
394 : };
395 : } scratch;
396 :
397 : #if FD_HAS_ZSTD
398 : ZSTD_DCtx * zstd_dctx;
399 : #endif
400 :
401 : fd_gui_ip_db_t dbip;
402 : };
403 :
404 : typedef struct fd_gui_peers_ctx fd_gui_peers_ctx_t;
405 :
406 : FD_PROTOTYPES_BEGIN
407 :
408 : FD_FN_CONST ulong
409 : fd_gui_peers_align( void );
410 :
411 : FD_FN_CONST ulong
412 : fd_gui_peers_footprint( ulong max_ws_conn_cnt );
413 :
414 : void *
415 : fd_gui_peers_new( void * shmem,
416 : fd_http_server_t * http,
417 : fd_topo_t * topo,
418 : ulong max_ws_conn_cnt,
419 : long now );
420 :
421 : fd_gui_peers_ctx_t *
422 : fd_gui_peers_join( void * shmem );
423 :
424 : /* fd_gui_peers_handle_gossip_message_rx parses gossip messages from the
425 : net_gossvf link for ingress messages and the gossip_net link for
426 : egress messages and tracks per-peer, per-message bytes. payload and
427 : payload_sz corresponds to the frag data after the network headers
428 : have been stripped. is_rx is true if the frag is an incoming message
429 : from the net_gossvf link. Otherwise, the frag is assumed to be an
430 : outgoing message from the gossip_net link. peer_sock is the ipv4
431 : address and port from the stripped net headers, which identifies the
432 : peers that sent or will receive the message.
433 :
434 : Note that gossip_net frags are unverified gossip messages from the
435 : network. Messages that cannot be parsed are ignored. */
436 : void
437 : fd_gui_peers_handle_gossip_message( fd_gui_peers_ctx_t * peers,
438 : uchar const * payload,
439 : ulong payload_sz,
440 : fd_gossip_socket_t const * peer_sock,
441 : int is_rx );
442 :
443 : /* fd_gui_peers_handle_gossip_message_tx parses frags on the gossip_out
444 : link and uses the contact info update to build up the peer table. */
445 :
446 : void
447 : fd_gui_peers_handle_gossip_update( fd_gui_peers_ctx_t * peers,
448 : fd_gossip_update_message_t const * update,
449 : long now );
450 :
451 : void
452 : fd_gui_peers_handle_vote( fd_gui_peers_ctx_t * peers,
453 : fd_pubkey_t const * vote_account,
454 : ulong vote_slot,
455 : int is_us );
456 :
457 : /* fd_gui_peers_update_delinquency is called infrequently (currently,
458 : once per slot) and scans the cluster for any nodes that are
459 : delinquent, publishing delinquency updates to the frontend. */
460 : void
461 : fd_gui_peers_update_delinquency( fd_gui_peers_ctx_t * peers,
462 : long now );
463 :
464 : /* fd_gui_peers_handle_epoch_info is called at the epoch boundary and
465 : publishes updates for peer stake information. */
466 : void
467 : fd_gui_peers_handle_epoch_info( fd_gui_peers_ctx_t * peers,
468 : fd_epoch_info_msg_t const * epoch_info,
469 : long now );
470 :
471 : void
472 : fd_gui_peers_handle_config_account( fd_gui_peers_ctx_t * peers,
473 : uchar const * data,
474 : ulong sz );
475 :
476 : /* fd_gui_peers_ws_message handles incoming websocket request payloads
477 : requesting peer-related responses. ws_conn_id is the connection id
478 : of the requester. data is a pointer to the start of the
479 : json-formatted request payload. data_len is the length of the
480 : request payload. */
481 : int
482 : fd_gui_peers_ws_message( fd_gui_peers_ctx_t * peers,
483 : ulong ws_conn_id,
484 : uchar const * data,
485 : ulong data_len );
486 :
487 : /* fd_gui_peers_ws_open is a callback which should be triggered when a
488 : new client opens a WebSocket connection. ws_conn_id is the
489 : connection id of the new client. now is a UNIX nanosecond timestamp
490 : for the current time. */
491 : void
492 : fd_gui_peers_ws_open( fd_gui_peers_ctx_t * peers,
493 : ulong ws_conn_id,
494 : long now );
495 :
496 : /* fd_gui_peers_ws_close is a callback which should be triggered when an
497 : existing client closes their WebSocket connection. ws_conn_id is the
498 : connection id of the client.*/
499 : void
500 : fd_gui_peers_ws_close( fd_gui_peers_ctx_t * peers,
501 : ulong ws_conn_id );
502 :
503 : /* fd_gui_peers_poll should be called in a the tile's main spin loop to
504 : periodically update peers internal state as well as publish new
505 : Websocket messages to clients. now is a UNIX nanosecond timestamp for
506 : the current time. */
507 : int
508 : fd_gui_peers_poll( fd_gui_peers_ctx_t * peers,
509 : long now );
510 :
511 : FD_PROTOTYPES_END
512 :
513 : #endif /* HEADER_fd_src_disco_gui_fd_gui_peers_h */
|