Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_gossip_fd_gossip_types_h 2 : #define HEADER_fd_src_flamenco_gossip_fd_gossip_types_h 3 : 4 : /* The gossip tile produces an output stream of update messages as it 5 : runs, which are published to a link for other tiles to consume. 6 : 7 : The formt and protocol of the update messages is defined here. 8 : 9 : Messages are published one by one incrementally, as they are 10 : received, although expirations or removals will not be published 11 : except for contact information which publishes a removal stream so 12 : that consumers of the updates can mirror the true gossip table. 13 : 14 : Not all gossip messages are published, and some are consumed just by 15 : the gossip tile itself. */ 16 : 17 : #include "../types/fd_types_custom.h" 18 : #include "../../util/net/fd_net_headers.h" 19 : 20 : /* The tag is the kind of gossip message that is being sent. It will be 21 : put both in the fragment signature, and in the message itself. */ 22 : 23 0 : #define FD_GOSSIP_UPDATE_TAG_CONTACT_INFO (0) 24 0 : #define FD_GOSSIP_UPDATE_TAG_CONTACT_INFO_REMOVE (1) 25 0 : #define FD_GOSSIP_UPDATE_TAG_LOWEST_SLOT (2) 26 0 : #define FD_GOSSIP_UPDATE_TAG_VOTE (3) 27 0 : #define FD_GOSSIP_UPDATE_TAG_DUPLICATE_SHRED (4) 28 0 : #define FD_GOSSIP_UPDATE_TAG_SNAPSHOT_HASHES (5) 29 : 30 : /* The maximum number of contact infos that may be present at any one 31 : time. If new contact infos are added, a removal will be issued first 32 : to make space. This is a hard limit, and the consumer of the contact 33 : info messages can assume it is always respected. 34 : 35 : The contact info messages are designed to be consumed in an 36 : incremental way. In particular, CONTACT_INFO and CONTACT_INFO_REMOVE 37 : messages are both sent with an idx field, which is the index of the 38 : contact info in an imaginary array of contact infos. Updates will 39 : always have the same idx for the same pubkey, and removes will 40 : likewise have the same idx for the pubkey being removed. A consumer 41 : of contact info updates can therefore simply maintain a local array 42 : of contact infos, and update it with the idx field. */ 43 : 44 0 : #define FD_CONTACT_INFO_TABLE_SIZE (32768UL) 45 : 46 6 : #define FD_CONTACT_INFO_SOCKET_GOSSIP ( 0) 47 0 : #define FD_CONTACT_INFO_SOCKET_SERVE_REPAIR_QUIC ( 1) 48 0 : #define FD_CONTACT_INFO_SOCKET_RPC ( 2) 49 0 : #define FD_CONTACT_INFO_SOCKET_RPC_PUBSUB ( 3) 50 0 : #define FD_CONTACT_INFO_SOCKET_SERVE_REPAIR ( 4) 51 0 : #define FD_CONTACT_INFO_SOCKET_TPU ( 5) 52 0 : #define FD_CONTACT_INFO_SOCKET_TPU_FORWARDS ( 6) 53 0 : #define FD_CONTACT_INFO_SOCKET_TPU_FORWARDS_QUIC ( 7) 54 0 : #define FD_CONTACT_INFO_SOCKET_TPU_QUIC ( 8) 55 0 : #define FD_CONTACT_INFO_SOCKET_TPU_VOTE ( 9) 56 0 : #define FD_CONTACT_INFO_SOCKET_TVU (10) 57 0 : #define FD_CONTACT_INFO_SOCKET_TVU_QUIC (11) 58 0 : #define FD_CONTACT_INFO_SOCKET_TPU_VOTE_QUIC (12) 59 0 : #define FD_CONTACT_INFO_SOCKET_ALPENGLOW (13) 60 45 : #define FD_CONTACT_INFO_SOCKET_CNT (14) 61 : 62 : /* https://github.com/anza-xyz/agave/blob/540d5bc56cd44e3cc61b179bd52e9a782a2c99e4/version/src/lib.rs#L95-L105 */ 63 : 64 : #define FD_CONTACT_INFO_VERSION_CLIENT_SOLANA_LABS (0) 65 : #define FD_CONTACT_INFO_VERSION_CLIENT_JITO_LABS (1) 66 : #define FD_CONTACT_INFO_VERSION_CLIENT_FRANKENDANCER (2) 67 : #define FD_CONTACT_INFO_VERSION_CLIENT_AGAVE (3) 68 : #define FD_CONTACT_INFO_VERSION_CLIENT_AGAVE_PALADIN (4) 69 3 : #define FD_CONTACT_INFO_VERSION_CLIENT_FIREDANCER (5) 70 : #define FD_CONTACT_INFO_VERSION_CLIENT_AGAVE_BAM (6) 71 : #define FD_CONTACT_INFO_VERSION_CLIENT_SIG (7) 72 : 73 : /* A contact info represents a peer node in the cluster that is 74 : publishing information about itself to the gossip network. It it 75 : sent when the tag is FD_GOSSIP_UPDATE_TAG_CONTACT_INFO. 76 : 77 : Contact infos are already deduplicated, so the same pubkey will not 78 : appear twice, and the number of contact infos outstanding is limited 79 : to FD_CONTACT_INFO_TABLE_SIZE. If more contact infos are received, 80 : the oldest ones are first removed with a 81 : FD_GOSSIP_UPDATE_TAG_CONTACT_INFO_REMOVE fragment. 82 : 83 : Contact infos are regularly updated, for example if a node changes 84 : its IP address or port. More typically nodes just periodically 85 : republish their contact info with an updated wallclock. When an 86 : existing contact info is updated, a FD_GOSSIP_UPDATE_TAG_CONTACT_INFO 87 : fragment is sent with the same pubkey. 88 : 89 : Contact information is not well-validated by the gossip network, and 90 : for example the wallclock may be old, or in the future, and the 91 : sockets may be unroutable or invalid (a private network), and the 92 : version fields are completely arbitrary. 93 : 94 : However, the pubkey is authenticated, as messages are signed. */ 95 : 96 : struct fd_contact_info { 97 : fd_pubkey_t pubkey; /* The identity public key of the peer node */ 98 : ushort shred_version; /* The shred version of the peer node, should be non-zero but not required */ 99 : 100 : long instance_creation_wallclock_nanos; 101 : long wallclock_nanos; /* The timestamp on the producer side of when the contact info was signed */ 102 : 103 : /* Peer nodes declare a list of ip:port pairs corresponding to 104 : standard Solana protocols that they support. A value of 0:0 105 : indicates the node does not advertise that protocol. For example, 106 : sockets[ FD_CONTACT_INFO_SOCKET_RPC ] is the IP address and port 107 : for the RPC service of the node. */ 108 : fd_ip4_port_t sockets[ FD_CONTACT_INFO_SOCKET_CNT ]; 109 : 110 : struct { 111 : ushort client; /* Any ushort in [0, USHORT_MAX], although typically one of FD_CONTACT_INFO_VERSION_CLIENT_* indicating the self-reported client version */ 112 : 113 : ushort major; /* The self-reported major version of the client */ 114 : ushort minor; /* The self-reported minor version of the client */ 115 : ushort patch; /* The self-reported patch version of the client */ 116 : 117 : uint commit; /* The self-reported commit hash of the client, in little-endian order, or 0 if no commit hash was provided */ 118 : uint feature_set; /* The self-reported feature set of the client, in little-endian order */ 119 : } version; 120 : }; 121 : 122 : typedef struct fd_contact_info fd_contact_info_t; 123 : 124 : /* A gossip vote represents a vote transaction that was sent to us by a 125 : peer node. It is sent when the tag is FD_GOSSIP_UPDATE_TAG_VOTE. 126 : Votes are typically sent over the TPU, but also via. gossip for 127 : redundancy. 128 : 129 : The transaction is not validated or parsed in any way yet, and in 130 : particular the signatures have not been verified. Transaction data 131 : is arbitrary and could be empty or corrupt or malicious. 132 : 133 : The source peer socket is included for use by downstream monitoring 134 : tools. */ 135 : 136 : struct fd_gossip_vote { 137 : fd_ip4_port_t socket; 138 : uchar vote_tower_index; 139 : ulong txn_sz; 140 : uchar txn[ 1232UL ]; 141 : }; 142 : 143 : typedef struct fd_gossip_vote fd_gossip_vote_t; 144 : 145 : #define FD_GOSSIP_DUPLICATE_SHRED_MAX_CHUNKS (1054UL) 146 : 147 : /* An edge case in the network is "equivocation" when a node publishes 148 : conflicting shred data for its leader slot. In future this may be 149 : a slashable offense, but for now it simply "proven" on the chain and 150 : communicated among peers. */ 151 : 152 : struct fd_gossip_duplicate_shred { 153 : ushort index; 154 : ulong slot; 155 : uchar num_chunks; 156 : uchar chunk_index; 157 : long wallclock; /* in nanos */ 158 : ulong chunk_len; 159 : uchar chunk[ FD_GOSSIP_DUPLICATE_SHRED_MAX_CHUNKS ]; 160 : }; 161 : 162 : typedef struct fd_gossip_duplicate_shred fd_gossip_duplicate_shred_t; 163 : 164 : struct fd_gossip_snapshot_hash_pair { 165 : ulong slot; 166 : uchar hash[ 32UL ]; 167 : }; 168 : 169 : typedef struct fd_gossip_snapshot_hash_pair fd_gossip_snapshot_hash_pair_t; 170 : 171 : #define FD_GOSSIP_SNAPSHOT_HASHES_MAX_INCREMENTAL (25UL) 172 : 173 : /* Each peer node which is serving snapshots will periodically 174 : publish a snapshot hash update, which contains the hashes of the 175 : latest snapshots it has available. This is sent when the tag is 176 : FD_GOSSIP_UPDATE_TAG_SNAPSHOT_HASHES. 177 : 178 : The full field indicates the full snapshot slot and hash, and then a 179 : list of recent incremental snapshots is provided which build on top 180 : of the full snapshot. */ 181 : 182 : struct fd_gossip_snapshot_hashes { 183 : fd_gossip_snapshot_hash_pair_t full[ 1 ]; 184 : 185 : ulong incremental_len; 186 : fd_gossip_snapshot_hash_pair_t incremental[ FD_GOSSIP_SNAPSHOT_HASHES_MAX_INCREMENTAL ]; 187 : }; 188 : 189 : typedef struct fd_gossip_snapshot_hashes fd_gossip_snapshot_hashes_t; 190 : 191 : struct fd_gossip_update_message { 192 : uchar tag; 193 : uchar origin_pubkey[ 32UL ]; 194 : ulong origin_stake; 195 : long wallclock_nanos; 196 : 197 : union { 198 : struct { 199 : ulong idx; /* Index into flat array to place this contact info, see comments on FD_CONTACT_INFO_TABLE_SIZE */ 200 : fd_contact_info_t contact_info[ 1 ]; 201 : } contact_info; 202 : 203 : struct { 204 : ulong idx; /* Index into flat array of contact info to remove, see FD_CONTACT_INFO_TABLE_SIZE */ 205 : } contact_info_remove; 206 : 207 : ulong lowest_slot; 208 : fd_gossip_vote_t vote; 209 : fd_gossip_duplicate_shred_t duplicate_shred; 210 : fd_gossip_snapshot_hashes_t snapshot_hashes; 211 : }; 212 : }; 213 : 214 : typedef struct fd_gossip_update_message fd_gossip_update_message_t; 215 : 216 : #endif /* HEADER_fd_src_flamenco_gossip_fd_gossip_types_h */