Line data Source code
1 : #ifndef HEADER_fd_src_discof_restore_utils_fd_sspeer_selector_h 2 : #define HEADER_fd_src_discof_restore_utils_fd_sspeer_selector_h 3 : 4 : /* The snapshot peer selector (sspeer_selector) continuously selects 5 : the most optimal snapshot peer to download snapshots from. The 6 : most optimal peer is defined as the closest peer that serves the 7 : most recent snapshot. */ 8 : 9 : #include "../../../util/fd_util_base.h" 10 : #include "../../../util/net/fd_net_headers.h" 11 : #include "fd_sspeer.h" 12 : 13 129 : #define FD_SSPEER_SELECTOR_MAGIC (0xF17EDA2CE5593350) /* FIREDANCE SSPING V0 */ 14 : 15 : /* Sentinel score returned by fd_sspeer_selector_best when no peer was 16 : found and by fd_sspeer_selector_add on failure. */ 17 108 : #define FD_SSPEER_SCORE_INVALID (ULONG_MAX) 18 : 19 : /* Maximum score a valid peer can have. FD_SSPEER_SCORE_MAX ensures a 20 : valid peer's score is never confused with FD_SSPEER_SCORE_INVALID. */ 21 906 : #define FD_SSPEER_SCORE_MAX (ULONG_MAX-1UL) 22 : 23 : /* Sentinel value indicating that a snapshot slot (full or incremental) 24 : is unknown or absent. */ 25 1650 : #define FD_SSPEER_SLOT_UNKNOWN (ULONG_MAX) 26 : 27 : /* Sentinel value indicating that peer latency has not been measured. */ 28 1002 : #define FD_SSPEER_LATENCY_UNKNOWN (ULONG_MAX) 29 : 30 : /* Plausibility bound: slots at or above this are silently dropped. 31 : ~10^10 is ~125 years of mainnet at 2.5 slots/s. */ 32 3 : #define FD_SSPEER_PLAUSIBLE_MAX_SLOT (10UL*1000UL*1000UL*1000UL) 33 : 34 : /* Return code for fd_sspeer_selector_update (internal). */ 35 90 : #define FD_SSPEER_UPDATE_SUCCESS ( 0) 36 : 37 : /* fd_sscluster_slot stores the max value for full and incremental 38 : slot computed from all tracked peers in the cluster. */ 39 : struct fd_sscluster_slot { 40 : ulong full; 41 : ulong incremental; 42 : }; 43 : 44 : typedef struct fd_sscluster_slot fd_sscluster_slot_t; 45 : 46 : /* fd_sspeer_t represents a selected peer from the snapshot peer 47 : selector, including the peer's address, resolved snapshot slots, 48 : and selector score. */ 49 : struct fd_sspeer { 50 : fd_sspeer_key_t key; /* key identifying the peer */ 51 : fd_ip4_port_t addr; /* address of the peer */ 52 : ulong full_slot; 53 : ulong incr_slot; 54 : ulong score; /* selector score of peer */ 55 : uchar full_hash[ FD_HASH_FOOTPRINT ]; 56 : uchar incr_hash[ FD_HASH_FOOTPRINT ]; 57 : }; 58 : 59 : typedef struct fd_sspeer fd_sspeer_t; 60 : 61 : struct fd_sspeer_selector_private; 62 : typedef struct fd_sspeer_selector_private fd_sspeer_selector_t; 63 : 64 : FD_PROTOTYPES_BEGIN 65 : 66 : FD_FN_CONST ulong 67 : fd_sspeer_selector_align( void ); 68 : 69 : FD_FN_CONST ulong 70 : fd_sspeer_selector_footprint( ulong max_peers ); 71 : 72 : void * 73 : fd_sspeer_selector_new( void * shmem, 74 : ulong max_peers, 75 : ulong seed ); 76 : 77 : fd_sspeer_selector_t * 78 : fd_sspeer_selector_join( void * shselector ); 79 : 80 : void * 81 : fd_sspeer_selector_leave( fd_sspeer_selector_t * selector ); 82 : 83 : void * 84 : fd_sspeer_selector_delete( void * shselector ); 85 : 86 : /* Update the selector when a ping response is received. The only 87 : value that can be updated is the latency. If multiple peers 88 : advertise the same address, the update is applied to all of them, 89 : since ssping cannot distinguish between these peers. It returns 90 : the number of peers that have been updated. */ 91 : ulong 92 : fd_sspeer_selector_update_on_ping( fd_sspeer_selector_t * selector, 93 : fd_ip4_port_t addr, 94 : ulong latency ); 95 : 96 : /* Add a peer to the selector. If the peer already exists, 97 : fd_sspeer_selector_add updates the existing peer's score using the 98 : given peer latency and snapshot info. Returns the updated score. 99 : 100 : Slot-based incremental clearing: for an existing peer, when 101 : incr_slot==FD_SSPEER_SLOT_UNKNOWN and full_slot!=FD_SSPEER_SLOT_UNKNOWN, 102 : the peer's incremental data is cleared if it is stale 103 : (peer->incr_slot < full_slot). For a new peer, full_hash and 104 : incr_hash are handled independently. 105 : 106 : Returns the updated score, or FD_SSPEER_SCORE_INVALID on failure. */ 107 : ulong 108 : fd_sspeer_selector_add( fd_sspeer_selector_t * selector, 109 : fd_sspeer_key_t const * key, 110 : fd_ip4_port_t addr, 111 : ulong peer_latency, 112 : ulong full_slot, 113 : ulong incr_slot, 114 : uchar const full_hash[ FD_HASH_FOOTPRINT ], 115 : uchar const incr_hash[ FD_HASH_FOOTPRINT ] ); 116 : 117 : /* Remove a peer from the selector. Peers are removed when they are 118 : not reachable or serving corrupted/malformed snapshots. This is a 119 : no-op if the peer does not exist in the selector. When removing by 120 : address, all peers advertising that address will be removed. */ 121 : void 122 : fd_sspeer_selector_remove( fd_sspeer_selector_t * selector, 123 : fd_sspeer_key_t const * key ); 124 : 125 : void 126 : fd_sspeer_selector_remove_by_addr( fd_sspeer_selector_t * selector, 127 : fd_ip4_port_t addr ); 128 : 129 : /* Select the best peer to download a snapshot from. incremental 130 : indicates to select a peer to download an incremental snapshot. If 131 : incremental is set, base_slot must be a valid full snapshot slot. 132 : Peers that do not offer an incremental snapshot 133 : (incr_slot==FD_SSPEER_SLOT_UNKNOWN) are excluded from incremental 134 : selection. */ 135 : fd_sspeer_t 136 : fd_sspeer_selector_best( fd_sspeer_selector_t * selector, 137 : int incremental, 138 : ulong base_slot ); 139 : 140 : /* Recompute the selector's internal cluster slot from the max of 141 : all tracked peers' slots. If the max changes, all peers are 142 : rescored. add() and remove() only mark the selector dirty; 143 : callers must invoke this function after mutations to apply the 144 : recomputation. No-op when the dirty flag is not set. */ 145 : void 146 : fd_sspeer_selector_process_cluster_slot( fd_sspeer_selector_t * selector ); 147 : 148 : /* Obtain the cluster slot from the selector. It is the highest 149 : of all tracked peers' full/incremental slots. */ 150 : fd_sscluster_slot_t 151 : fd_sspeer_selector_cluster_slot( fd_sspeer_selector_t * selector ); 152 : 153 : /* Helper functions to count how many elements exist in both peer maps 154 : (by_key and by_addr). Mainly used in unit tests. These are not 155 : optimized for performance. */ 156 : ulong 157 : fd_sspeer_selector_peer_map_by_key_ele_cnt( fd_sspeer_selector_t * selector ); 158 : 159 : ulong 160 : fd_sspeer_selector_peer_map_by_addr_ele_cnt( fd_sspeer_selector_t * selector ); 161 : 162 : FD_PROTOTYPES_END 163 : 164 : #endif /* HEADER_fd_src_discof_restore_utils_fd_sspeer_selector_h */