LCOV - code coverage report
Current view: top level - disco/gui - fd_gui_peers.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 49 0.0 %
Date: 2025-10-27 04:40:00 Functions: 0 12 0.0 %

          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 "../../util/net/fd_net_headers.h"
      18             : #include "../../disco/metrics/fd_metrics.h"
      19             : #include "../../flamenco/gossip/fd_gossip_types.h"
      20             : #include "../../discof/replay/fd_replay_tile.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             : #define FD_GUI_PEERS_VALIDATOR_INFO_NAME_SZ     ( 64UL)
      27             : #define FD_GUI_PEERS_VALIDATOR_INFO_WEBSITE_SZ  (128UL)
      28             : #define FD_GUI_PEERS_VALIDATOR_INFO_DETAILS_SZ  (256UL)
      29             : #define FD_GUI_PEERS_VALIDATOR_INFO_ICON_URI_SZ (128UL)
      30             : 
      31             : #define FD_GUI_PEERS_NODE_NOP    (0)
      32           0 : #define FD_GUI_PEERS_NODE_ADD    (1)
      33           0 : #define FD_GUI_PEERS_NODE_UPDATE (2)
      34           0 : #define FD_GUI_PEERS_NODE_DELETE (3)
      35             : 
      36           0 : #define FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT                 (256UL) /* maximum number of maintained active sort keys */
      37           0 : #define FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ                    (200UL) /* the maximum number of rows a client can request for a table viewport */
      38           0 : #define FD_GUI_PEERS_WS_VIEWPORT_UPDATE_INTERVAL_MILLIS    ( 100L)
      39           0 : #define FD_GUI_PEERS_METRIC_RATE_UPDATE_INTERVAL_MILLIS    ( 100L)
      40           0 : #define FD_GUI_PEERS_GOSSIP_STATS_UPDATE_INTERVAL_MILLIS   ( 100L)
      41             : 
      42           0 : #define FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT (64UL)
      43             : 
      44             : /* Some table columns are rates of change, which require keeping a
      45             :    historical value / timestamp. */
      46             : struct fd_gui_peers_metric_rate {
      47             :   ulong cur;
      48             :   ulong ref;
      49             :   long rate; /* units per sec. live_table treaps use this field to sort table entries */
      50             : };
      51             : typedef struct fd_gui_peers_metric_rate fd_gui_peers_metric_rate_t;
      52             : 
      53             : struct fd_gui_peers_vote {
      54             :   fd_pubkey_t node_account;
      55             :   fd_pubkey_t vote_account;
      56             :   ulong       stake;
      57             :   ulong       last_vote_slot;
      58             :   long        last_vote_timestamp;
      59             :   uchar       commission;
      60             :   ulong       epoch;
      61             :   ulong       epoch_credits;
      62             : };
      63             : 
      64             : typedef struct fd_gui_peers_vote fd_gui_peers_vote_t;
      65             : 
      66             : struct fd_gui_peers_node {
      67             :   int valid;
      68             :   long update_time_nanos;
      69             :   fd_contact_info_t contact_info;
      70             : 
      71             :   fd_gui_peers_metric_rate_t gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
      72             :   fd_gui_peers_metric_rate_t gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
      73             :   fd_gui_peers_metric_rate_t gossvf_rx_sum; /* sum of gossvf_rx */
      74             :   fd_gui_peers_metric_rate_t gossip_tx_sum; /* sum of gossip_tx */
      75             : 
      76             :   int  has_val_info;
      77             :   char name    [ FD_GUI_PEERS_VALIDATOR_INFO_NAME_SZ     ];
      78             :   char website [ FD_GUI_PEERS_VALIDATOR_INFO_WEBSITE_SZ  ];
      79             :   char details [ FD_GUI_PEERS_VALIDATOR_INFO_DETAILS_SZ  ];
      80             :   char icon_uri[ FD_GUI_PEERS_VALIDATOR_INFO_ICON_URI_SZ ];
      81             : 
      82             :   int         has_vote_info;
      83             :   fd_pubkey_t vote_account;
      84             :   ulong       stake;
      85             :   ulong       last_vote_slot;
      86             :   long        last_vote_timestamp;
      87             :   uchar       commission;
      88             :   ulong       epoch;
      89             :   ulong       epoch_credits;
      90             :   int         delinquent;
      91             : 
      92             :   struct {
      93             :     ulong next;
      94             :     ulong prev;
      95             :   } pubkey_map;
      96             : 
      97             :   struct {
      98             :     ulong next;
      99             :     ulong prev;
     100             :   } sock_map;
     101             : 
     102             :   struct {
     103             :     ulong parent;
     104             :     ulong left;
     105             :     ulong right;
     106             :     ulong prio;
     107             :     ulong next;
     108             :     ulong prev;
     109             :   } treaps_live_table[ FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT ];
     110             :   struct {
     111             :     ulong next;
     112             :     ulong prev;
     113             :   } dlist_live_table;
     114             :   ulong sort_keys_live_table;
     115             : 
     116             :   struct {
     117             :     ulong parent;
     118             :     ulong left;
     119             :     ulong right;
     120             :     ulong prio;
     121             :     ulong next;
     122             :     ulong prev;
     123             :   } treaps_bandwidth_tracking[ 2UL ];
     124             :     struct {
     125             :     ulong next;
     126             :     ulong prev;
     127             :   } dlist_bandwidth_tracking;
     128             :   ulong sort_keys_bandwidth_tracking;
     129             : };
     130             : typedef struct fd_gui_peers_node fd_gui_peers_node_t;
     131             : 
     132             : struct fd_gui_peers_gossip_stats {
     133             :   long  sample_time;
     134             :   ulong network_health_pull_response_msg_rx_success;
     135             :   ulong network_health_pull_response_msg_rx_failure;
     136             :   ulong network_health_push_msg_rx_success;
     137             :   ulong network_health_push_msg_rx_failure;
     138             :   ulong network_health_push_crds_rx_duplicate;
     139             :   ulong network_health_pull_response_crds_rx_duplicate;
     140             :   ulong network_health_push_crds_rx_success;
     141             :   ulong network_health_push_crds_rx_failure;
     142             :   ulong network_health_pull_response_crds_rx_success;
     143             :   ulong network_health_pull_response_crds_rx_failure;
     144             :   ulong network_health_push_msg_tx;
     145             :   ulong network_health_pull_response_msg_tx;
     146             :   ulong network_health_total_stake; /* lamports */
     147             :   ulong network_health_total_peers;
     148             :   ulong network_health_connected_stake; /* lamports */
     149             :   ulong network_health_connected_staked_peers;
     150             :   ulong network_health_connected_unstaked_peers;
     151             :   ulong network_ingress_total_bytes;
     152             :   ulong network_ingress_peer_sz;
     153             :   long  network_ingress_peer_bytes_per_sec   [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     154             :   char  network_ingress_peer_names           [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ][ FD_GUI_PEERS_VALIDATOR_INFO_NAME_SZ ];
     155             :   fd_pubkey_t network_ingress_peer_identities[ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     156             :   long  network_ingress_total_bytes_per_sec;
     157             :   ulong network_egress_total_bytes;
     158             :   ulong network_egress_peer_sz;
     159             :   long  network_egress_peer_bytes_per_sec   [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     160             :   char  network_egress_peer_names           [ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ][ FD_GUI_PEERS_VALIDATOR_INFO_NAME_SZ ];
     161             :   fd_pubkey_t network_egress_peer_identities[ FD_GUI_PEERS_GOSSIP_TOP_PEERS_CNT ];
     162             :   long  network_egress_total_bytes_per_sec;
     163             :   ulong storage_capacity;
     164             :   ulong storage_expired_cnt;
     165             :   ulong storage_evicted_cnt;
     166             :   ulong storage_active_cnt[ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
     167             :   ulong storage_cnt_tx    [ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
     168             :   ulong storage_bytes_tx  [ FD_METRICS_ENUM_CRDS_VALUE_CNT ];
     169             :   ulong messages_push_rx_cnt;
     170             :   ulong messages_push_tx_cnt;
     171             :   ulong messages_pull_response_rx_cnt;
     172             :   ulong messages_pull_response_tx_cnt;
     173             :   ulong messages_bytes_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     174             :   ulong messages_count_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     175             :   ulong messages_bytes_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     176             :   ulong messages_count_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_CNT ];
     177             : };
     178             : typedef struct fd_gui_peers_gossip_stats fd_gui_peers_gossip_stats_t;
     179             : 
     180             : #define MAP_NAME  fd_gui_peers_node_pubkey_map
     181           0 : #define MAP_ELE_T fd_gui_peers_node_t
     182             : #define MAP_KEY_T fd_pubkey_t
     183           0 : #define MAP_KEY   contact_info.pubkey
     184           0 : #define MAP_IDX_T ulong
     185           0 : #define MAP_NEXT  pubkey_map.next
     186           0 : #define MAP_PREV  pubkey_map.prev
     187           0 : #define MAP_KEY_HASH(k,s) ((s) ^ fd_ulong_hash( (k)->ul[ 0 ] ))
     188           0 : #define MAP_KEY_EQ(k0,k1) (!memcmp((k0)->uc, (k1)->uc, 32UL))
     189             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
     190             : #include "../../util/tmpl/fd_map_chain.c"
     191             : 
     192             : #define MAP_NAME  fd_gui_peers_node_sock_map
     193           0 : #define MAP_ELE_T fd_gui_peers_node_t
     194             : #define MAP_KEY_T fd_ip4_port_t
     195           0 : #define MAP_KEY   contact_info.sockets[ FD_CONTACT_INFO_SOCKET_GOSSIP ]
     196           0 : #define MAP_IDX_T ulong
     197           0 : #define MAP_NEXT  sock_map.next
     198           0 : #define MAP_PREV  sock_map.prev
     199           0 : #define MAP_KEY_HASH(k,s) ( fd_hash( (s), (k), sizeof(uint) + sizeof(ushort) ) )
     200           0 : #define MAP_KEY_EQ(k0,k1) ((k0)->l==(k1)->l )
     201             : #define MAP_OPTIMIZE_RANDOM_ACCESS_REMOVAL 1
     202             : #define MAP_MULTI 1
     203             : #include "../../util/tmpl/fd_map_chain.c"
     204             : 
     205           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; }
     206           0 : static int live_table_col_long_lt  ( void const * a, void const * b ) { return *(long *)a < *(long *)b;                                            }
     207           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);              }
     208             : 
     209             : #define LIVE_TABLE_NAME fd_gui_peers_live_table
     210           0 : #define LIVE_TABLE_TREAP treaps_live_table
     211           0 : #define LIVE_TABLE_SORT_KEYS sort_keys_live_table
     212           0 : #define LIVE_TABLE_DLIST dlist_live_table
     213           0 : #define LIVE_TABLE_COLUMN_CNT (6UL)
     214           0 : #define LIVE_TABLE_MAX_SORT_KEY_CNT FD_GUI_PEERS_CI_TABLE_SORT_KEY_CNT
     215             : #define LIVE_TABLE_ROW_T fd_gui_peers_node_t
     216           0 : #define LIVE_TABLE_COLUMNS LIVE_TABLE_COL_ARRAY( \
     217           0 :   LIVE_TABLE_COL_ENTRY( "Ingress Push", gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate,          live_table_col_long_lt   ), \
     218           0 :   LIVE_TABLE_COL_ENTRY( "Ingress Pull", gossvf_rx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate, live_table_col_long_lt   ), \
     219           0 :   LIVE_TABLE_COL_ENTRY( "Egress Push",  gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PUSH_IDX ].rate,          live_table_col_long_lt   ), \
     220           0 :   LIVE_TABLE_COL_ENTRY( "Egress Pull",  gossip_tx[ FD_METRICS_ENUM_GOSSIP_MESSAGE_V_PULL_RESPONSE_IDX ].rate, live_table_col_long_lt   ), \
     221           0 :   LIVE_TABLE_COL_ENTRY( "Pubkey",       contact_info.pubkey,                                                  live_table_col_pubkey_lt ), \
     222           0 :   LIVE_TABLE_COL_ENTRY( "IP Addr",      contact_info.sockets[ FD_CONTACT_INFO_SOCKET_GOSSIP ].addr,           live_table_col_ipv4_lt   )  )
     223             : #include "fd_gui_live_table_tmpl.c"
     224             : 
     225           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 }, .dir = { -1, -1, -1, -1, -1, -1 } })
     226             : 
     227             : #define LIVE_TABLE_NAME fd_gui_peers_bandwidth_tracking
     228           0 : #define LIVE_TABLE_TREAP treaps_bandwidth_tracking
     229           0 : #define LIVE_TABLE_SORT_KEYS sort_keys_bandwidth_tracking
     230           0 : #define LIVE_TABLE_DLIST dlist_bandwidth_tracking
     231           0 : #define LIVE_TABLE_COLUMN_CNT (2UL)
     232           0 : #define LIVE_TABLE_MAX_SORT_KEY_CNT (2UL)
     233             : #define LIVE_TABLE_ROW_T fd_gui_peers_node_t
     234           0 : #define LIVE_TABLE_COLUMNS LIVE_TABLE_COL_ARRAY( \
     235           0 :   LIVE_TABLE_COL_ENTRY( "Ingress Total", gossvf_rx_sum.rate, live_table_col_long_lt ), \
     236           0 :   LIVE_TABLE_COL_ENTRY( "Egress Total",  gossip_tx_sum.rate, live_table_col_long_lt )  )
     237             : #include "fd_gui_live_table_tmpl.c"
     238             : 
     239           0 : #define FD_GUI_PEERS_BW_TRACKING_INGRESS_SORT_KEY ((fd_gui_peers_bandwidth_tracking_sort_key_t){ .col = { 0, 1 }, .dir = { -1, 0 } })
     240           0 : #define FD_GUI_PEERS_BW_TRACKING_EGRESS_SORT_KEY  ((fd_gui_peers_bandwidth_tracking_sort_key_t){ .col = { 0, 1 }, .dir = { 0, -1 } })
     241             : 
     242             : struct fd_gui_peers_ws_conn {
     243             :   int connected;
     244             :   long connected_time;
     245             : 
     246             :   ulong start_row;
     247             :   ulong row_cnt;
     248             :   fd_gui_peers_node_t viewport[ FD_GUI_PEERS_WS_VIEWPORT_MAX_SZ ];
     249             :   fd_gui_peers_live_table_sort_key_t sort_key;
     250             : };
     251             : typedef struct fd_gui_peers_ws_conn fd_gui_peers_ws_conn_t;
     252             : struct fd_gui_peers_ctx {
     253             :   long next_client_nanos; /* ns timestamp when we'll service the next ws client */
     254             :   long next_metric_rate_update_nanos; /* ns timestamp when we'll next update rate-of-change metrics */
     255             :   long next_gossip_stats_update_nanos; /* ns timestamp when we'll next broadcast out gossip stats message */
     256             : 
     257             :   fd_gui_peers_node_pubkey_map_t * node_pubkey_map;
     258             :   fd_gui_peers_node_sock_map_t  * node_sock_map;
     259             :   fd_gui_peers_live_table_t * live_table;
     260             :   fd_gui_peers_bandwidth_tracking_t * bw_tracking;
     261             : 
     262             :   fd_http_server_t * http;
     263             :   fd_topo_t * topo;
     264             : 
     265             :   ulong max_ws_conn_cnt;
     266             :   ulong open_ws_conn_cnt;
     267             :   ulong active_ws_conn_id;
     268             :   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 */
     269             : 
     270             :   fd_gui_peers_gossip_stats_t gossip_stats  [ 1 ];
     271             :   fd_gui_peers_node_t contact_info_table[ FD_CONTACT_INFO_TABLE_SIZE ];
     272             : 
     273             :   fd_gui_peers_vote_t votes        [ FD_RUNTIME_MAX_VOTE_ACCOUNTS ];
     274             :   fd_gui_peers_vote_t votes_scratch[ FD_RUNTIME_MAX_VOTE_ACCOUNTS ]; /* for fast stable sort */
     275             : };
     276             : typedef struct fd_gui_peers_ctx fd_gui_peers_ctx_t;
     277             : 
     278             : FD_PROTOTYPES_BEGIN
     279             : 
     280             : FD_FN_CONST ulong
     281             : fd_gui_peers_align( void );
     282             : 
     283             : FD_FN_CONST ulong
     284             : fd_gui_peers_footprint( ulong max_ws_conn_cnt );
     285             : 
     286             : void *
     287             : fd_gui_peers_new( void *             shmem,
     288             :                   fd_http_server_t * http,
     289             :                   fd_topo_t *        topo,
     290             :                   ulong              max_ws_conn_cnt,
     291             :                   long               now );
     292             : 
     293             : fd_gui_peers_ctx_t *
     294             : fd_gui_peers_join( void * shmem );
     295             : 
     296             : /* fd_gui_peers_handle_gossip_message_rx parses gossip messages from the
     297             :    net_gossvf link for ingress messages and the gossip_net link for
     298             :    egress messages and tracks per-peer, per-message bytes.  payload and
     299             :    payload_sz corresponds to the frag data after the network headers
     300             :    have been stripped. is_rx is true if the frag is an incoming message
     301             :    from the net_gossvf link. Otherwise, the frag is assumed to be an
     302             :    outgoing message from the gossip_net link. peer_sock is the ipv4
     303             :    address and port from the stripped net headers, which identifies the
     304             :    peers that sent or will receive the message.
     305             : 
     306             :    Note that gossip_net frags are unverified gossip messages from the
     307             :    network.  Messages that cannot be parsed are ignored. */
     308             : void
     309             : fd_gui_peers_handle_gossip_message( fd_gui_peers_ctx_t *  peers,
     310             :                                     uchar const *         payload,
     311             :                                     ulong                 payload_sz,
     312             :                                     fd_ip4_port_t const * peer_sock,
     313             :                                     int                   is_rx );
     314             : 
     315             : /* fd_gui_peers_handle_gossip_message_tx parses frags on the gossip_out
     316             :    link and uses the contact info update to build up the peer table.
     317             :    */
     318             : void
     319             : fd_gui_peers_handle_gossip_update( fd_gui_peers_ctx_t *               peers,
     320             :                                    fd_gossip_update_message_t const * update,
     321             :                                    long                               now );
     322             : 
     323             : void
     324             : fd_gui_peers_handle_vote_update( fd_gui_peers_ctx_t *  peers,
     325             :                                  fd_gui_peers_vote_t * votes,
     326             :                                  ulong                 vote_cnt,
     327             :                                  long                  now );
     328             : 
     329             : /* fd_gui_peers_ws_message handles incoming websocket request payloads
     330             :    requesting peer-related responses.  ws_conn_id is the connection id
     331             :    of the requester.  data is a pointer to the start of the
     332             :    json-formatted request payload.  data_len is the length of the
     333             :    request payload. */
     334             : int
     335             : fd_gui_peers_ws_message( fd_gui_peers_ctx_t * peers,
     336             :                          ulong                ws_conn_id,
     337             :                          uchar const *        data,
     338             :                          ulong                data_len );
     339             : 
     340             : /* fd_gui_peers_ws_open is a callback which should be triggered when a
     341             :    new client opens a WebSocket connection.  ws_conn_id is the
     342             :    connection id of the new client.  now is a UNIX nanosecond timestamp
     343             :    for the current time. */
     344             : void
     345             : fd_gui_peers_ws_open( fd_gui_peers_ctx_t * peers, ulong ws_conn_id, long now );
     346             : 
     347             : /* fd_gui_peers_ws_close is a callback which should be triggered when an
     348             :    existing client closes their WebSocket connection.  ws_conn_id is the
     349             :    connection id of the client.*/
     350             : void
     351             : fd_gui_peers_ws_close( fd_gui_peers_ctx_t * peers, ulong ws_conn_id );
     352             : 
     353             : /* fd_gui_peers_poll should be called in a the tile's main spin loop to
     354             :    periodically update peers internal state as well as publish new
     355             :    Websocket messages to clients. now is a UNIX nanosecond timestamp for
     356             :    the current time. */
     357             : int
     358             : fd_gui_peers_poll( fd_gui_peers_ctx_t * peers, long now  );
     359             : 
     360             : FD_PROTOTYPES_END
     361             : 
     362             : #endif /* HEADER_fd_src_disco_gui_fd_gui_peers_h */

Generated by: LCOV version 1.14