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 0 : #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 : #define FD_CONTACT_INFO_SOCKET_ALPENGLOW (13) 60 0 : #define FD_CONTACT_INFO_SOCKET_LAST (13) 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 0 : #define FD_CONTACT_INFO_VERSION_CLIENT_FIREDANCER (2) 67 : #define FD_CONTACT_INFO_VERSION_CLIENT_AGAVE (3) 68 : 69 : /* A contact info represents a peer node in the cluster that is 70 : publishing information about itself to the gossip network. It it 71 : sent when the tag is FD_GOSSIP_UPDATE_TAG_CONTACT_INFO. 72 : 73 : Contact infos are already deduplicated, so the same pubkey will not 74 : appear twice, and the number of contact infos outstanding is limited 75 : to FD_CONTACT_INFO_TABLE_SIZE. If more contact infos are received, 76 : the oldest ones are first removed with a 77 : FD_GOSSIP_UPDATE_TAG_CONTACT_INFO_REMOVE fragment. 78 : 79 : Contact infos are regularly updated, for example if a node changes 80 : its IP address or port. More typically nodes just periodically 81 : republish their contact info with an updated wallclock. When an 82 : existing contact info is updated, a FD_GOSSIP_UPDATE_TAG_CONTACT_INFO 83 : fragment is sent with the same pubkey. 84 : 85 : Contact information is not well-validated by the gossip network, and 86 : for example the wallclock may be old, or in the future, and the 87 : sockets may be unroutable or invalid (a private network), and the 88 : version fields are completely arbitrary. 89 : 90 : However, the pubkey is authenticated, as messages are signed. */ 91 : 92 : struct fd_contact_info { 93 : fd_pubkey_t pubkey; /* The identity public key of the peer node */ 94 : ushort shred_version; /* The shred version of the peer node, should be non-zero but not required */ 95 : 96 : long instance_creation_wallclock_nanos; 97 : long wallclock_nanos; /* The timestamp on the producer side of when the contact info was signed */ 98 : 99 : /* Peer nodes declare a list of ip:port pairs corresponding to 100 : standard Solana protocols that they support. A value of 0:0 101 : indicates the node does not advertise that protocol. For example, 102 : sockets[ FD_CONTACT_INFO_SOCKET_RPC ] is the IP address and port 103 : for the RPC service of the node. */ 104 : fd_ip4_port_t sockets[ FD_CONTACT_INFO_SOCKET_LAST+1UL ]; 105 : 106 : struct { 107 : ushort client; /* Any ushort in [0, USHORT_MAX], although typically one of FD_CONTACT_INFO_VERSION_CLIENT_* indicating the self-reported client version */ 108 : 109 : ushort major; /* The self-reported major version of the client */ 110 : ushort minor; /* The self-reported minor version of the client */ 111 : ushort patch; /* The self-reported patch version of the client */ 112 : 113 : uint commit; /* The self-reported commit hash of the client, in little-endian order, or 0 if no commit hash was provided */ 114 : uint feature_set; /* The self-reported feature set of the client, in little-endian order */ 115 : } version; 116 : }; 117 : 118 : typedef struct fd_contact_info fd_contact_info_t; 119 : 120 : /* A gossip vote represents a vote transaction that was sent to us by a 121 : peer node. It is sent when the tag is FD_GOSSIP_UPDATE_TAG_VOTE. 122 : Votes are typically sent over the TPU, but also via. gossip for 123 : redundancy. 124 : 125 : The transaction is not validated or parsed in any way yet, and in 126 : particular the signatures have not been verified. Transaction data 127 : is arbitrary and could be empty or corrupt or malicious. */ 128 : 129 : struct fd_gossip_vote { 130 : uchar vote_tower_index; 131 : ulong txn_sz; 132 : uchar txn[ 1232UL ]; 133 : }; 134 : 135 : typedef struct fd_gossip_vote fd_gossip_vote_t; 136 : 137 : #define FD_GOSSIP_DUPLICATE_SHRED_MAX_CHUNKS (1054UL) 138 : 139 : /* An edge case in the network is "equivocation" when a node publishes 140 : conflicting shred data for its leader slot. In future this may be 141 : a slashable offense, but for now it simply "proven" on the chain and 142 : communicated among peers. */ 143 : 144 : struct fd_gossip_duplicate_shred { 145 : ushort index; 146 : ulong slot; 147 : uchar num_chunks; 148 : uchar chunk_index; 149 : long wallclock; /* in nanos */ 150 : ulong chunk_len; 151 : uchar chunk[ FD_GOSSIP_DUPLICATE_SHRED_MAX_CHUNKS ]; 152 : }; 153 : 154 : typedef struct fd_gossip_duplicate_shred fd_gossip_duplicate_shred_t; 155 : 156 : struct fd_gossip_snapshot_hash_pair { 157 : ulong slot; 158 : uchar hash[ 32UL ]; 159 : }; 160 : 161 : typedef struct fd_gossip_snapshot_hash_pair fd_gossip_snapshot_hash_pair_t; 162 : 163 : #define FD_GOSSIP_SNAPSHOT_HASHES_MAX_INCREMENTAL (25UL) 164 : 165 : /* Each peer node which is serving snapshots will periodically 166 : publish a snapshot hash update, which contains the hashes of the 167 : latest snapshots it has available. This is sent when the tag is 168 : FD_GOSSIP_UPDATE_TAG_SNAPSHOT_HASHES. 169 : 170 : The full field indicates the full snapshot slot and hash, and then a 171 : list of recent incremental snapshots is provided which build on top 172 : of the full snapshot. */ 173 : 174 : struct fd_gossip_snapshot_hashes { 175 : fd_gossip_snapshot_hash_pair_t full[ 1 ]; 176 : 177 : ulong incremental_len; 178 : fd_gossip_snapshot_hash_pair_t incremental[ FD_GOSSIP_SNAPSHOT_HASHES_MAX_INCREMENTAL ]; 179 : }; 180 : 181 : typedef struct fd_gossip_snapshot_hashes fd_gossip_snapshot_hashes_t; 182 : 183 : struct fd_gossip_update_message { 184 : uchar tag; 185 : uchar origin_pubkey[ 32UL ]; 186 : ulong origin_stake; 187 : long wallclock_nanos; 188 : 189 : union { 190 : struct { 191 : ulong idx; /* Index into flat array to place this contact info, see comments on FD_CONTACT_INFO_TABLE_SIZE */ 192 : fd_contact_info_t contact_info[ 1 ]; 193 : } contact_info; 194 : 195 : struct { 196 : ulong idx; /* Index into flat array of contact info to remove, see FD_CONTACT_INFO_TABLE_SIZE */ 197 : } contact_info_remove; 198 : 199 : ulong lowest_slot; 200 : fd_gossip_vote_t vote; 201 : fd_gossip_duplicate_shred_t duplicate_shred; 202 : fd_gossip_snapshot_hashes_t snapshot_hashes; 203 : }; 204 : }; 205 : 206 : typedef struct fd_gossip_update_message fd_gossip_update_message_t; 207 : 208 : #endif /* HEADER_fd_src_flamenco_gossip_fd_gossip_types_h */