Line data Source code
1 : #ifndef HEADER_fd_src_disco_bundle_fd_bundle_tile_private_h 2 : #define HEADER_fd_src_disco_bundle_fd_bundle_tile_private_h 3 : 4 : #include "fd_bundle_auth.h" 5 : #include "fd_keepalive.h" 6 : #include "../stem/fd_stem.h" 7 : #include "../keyguard/fd_keyswitch.h" 8 : #include "../keyguard/fd_keyguard_client.h" 9 : #include "../../waltz/grpc/fd_grpc_client.h" 10 : #include "../../waltz/resolv/fd_netdb.h" 11 : #include "../../waltz/fd_rtt_est.h" 12 : #include "../../util/alloc/fd_alloc.h" 13 : #include "../../util/hist/fd_histf.h" 14 : #define FD_BUNDLE_CLIENT_MAX_TXN_PER_BUNDLE (5UL) 15 : 16 : /* Pending transaction buffer. gRPC callbacks push decoded transactions 17 : here. after_credit drains one bundle per call by writing to dcache 18 : and calling fd_stem_publish. 19 : 20 : Sized to match the bundle_verif output link depth. */ 21 : 22 : struct fd_bundle_pending_txn { 23 : uchar payload[ FD_TXN_MTU ]; 24 : ushort payload_sz; 25 : uint source_ipv4; 26 : ulong sig; 27 : ulong bundle_seq; 28 : ulong bundle_txn_cnt; 29 : uchar commission; 30 : uchar commission_pubkey[ 32 ]; 31 : }; 32 : 33 : typedef struct fd_bundle_pending_txn fd_bundle_pending_txn_t; 34 : 35 : #define DEQUE_NAME pending_txn 36 0 : #define DEQUE_T fd_bundle_pending_txn_t 37 : #include "../../util/tmpl/fd_deque_dynamic.c" 38 : 39 : /* Returns true if the drain loop should continue after popping an 40 : entry. Bundles drain atomically (all txns with matching bundle_seq). 41 : Packets drain up to burst consecutive entries. */ 42 : 43 : static inline int 44 : fd_bundle_drain_continue( fd_bundle_pending_txn_t * txns, 45 : ulong drain_sig, 46 : ulong drain_seq, 47 : ulong drain_cnt, 48 0 : ulong burst ) { 49 0 : if( pending_txn_empty( txns ) ) return 0; 50 0 : if( drain_sig==1UL ) return pending_txn_peek_head( txns )->bundle_seq==drain_seq; 51 0 : return drain_cnt<burst && pending_txn_peek_head( txns )->sig==0UL; 52 0 : } 53 : 54 : #if FD_HAS_OPENSSL 55 : #include <openssl/ssl.h> /* SSL_CTX */ 56 : #endif 57 : 58 : struct fd_bundle_out_ctx { 59 : ulong idx; 60 : fd_wksp_t * mem; 61 : ulong chunk0; 62 : ulong wmark; 63 : ulong chunk; 64 : }; 65 : 66 : typedef struct fd_bundle_out_ctx fd_bundle_out_ctx_t; 67 : 68 : /* fd_bundle_metrics_t contains private metric counters. These get 69 : published to fd_metrics periodically. */ 70 : 71 : struct fd_bundle_metrics { 72 : ulong txn_received_cnt; 73 : ulong bundle_received_cnt; 74 : ulong packet_received_cnt; 75 : ulong proto_received_bytes; 76 : ulong shredstream_heartbeat_cnt; 77 : ulong ping_ack_cnt; 78 : 79 : ulong decode_fail_cnt; 80 : ulong transport_fail_cnt; 81 : ulong missing_builder_info_fail_cnt; 82 : ulong backpressure_drop_cnt; 83 : 84 : fd_histf_t msg_rx_delay[1]; 85 : }; 86 : 87 : typedef struct fd_bundle_metrics fd_bundle_metrics_t; 88 : 89 : /* fd_bundle_tile_t is the context object provided to callbacks from 90 : stem, and contains all state needed to progress the tile. */ 91 : 92 : struct fd_bundle_tile { 93 : /* Key switch */ 94 : fd_keyswitch_t * keyswitch; 95 : 96 : /* Key guard */ 97 : fd_keyguard_client_t keyguard_client[1]; 98 : 99 : uint is_ssl : 1; 100 : int keylog_fd; 101 : # if FD_HAS_OPENSSL 102 : /* OpenSSL */ 103 : SSL_CTX * ssl_ctx; 104 : SSL * ssl; 105 : fd_alloc_t * ssl_alloc; 106 : # endif /* FD_HAS_OPENSSL */ 107 : 108 : /* Config */ 109 : char server_fqdn[ 256 ]; /* cstr */ 110 : ulong server_fqdn_len; 111 : char server_sni[ 256 ]; /* cstr */ 112 : ulong server_sni_len; 113 : ushort server_tcp_port; 114 : 115 : /* Resolver */ 116 : fd_netdb_fds_t netdb_fds[1]; 117 : uint server_ip4_addr; /* last DNS lookup result */ 118 : 119 : /* TCP socket */ 120 : int tcp_sock; 121 : int so_rcvbuf; 122 : uint tcp_sock_connected : 1; 123 : uint defer_reset : 1; 124 : long cached_ts; 125 : 126 : /* Keepalive via HTTP/2 PINGs (randomized) */ 127 : long keepalive_interval; 128 : fd_keepalive_t keepalive[1]; 129 : fd_rtt_estimate_t rtt[1]; 130 : 131 : /* gRPC client */ 132 : void * grpc_client_mem; 133 : ulong grpc_buf_max; 134 : fd_grpc_client_t * grpc_client; 135 : fd_grpc_client_metrics_t grpc_metrics[1]; 136 : ulong map_seed; 137 : 138 : /* Bundle authenticator */ 139 : fd_bundle_auther_t auther; 140 : 141 : /* Bundle block builder info */ 142 : uchar builder_pubkey[ 32 ]; 143 : uchar builder_commission; /* in [0,100] (percent) */ 144 : uchar builder_info_avail : 1; /* Block builder info available? (potentially stale) */ 145 : uchar builder_info_wait : 1; /* Request already in-flight? */ 146 : long builder_info_valid_until; 147 : 148 : /* Bundle subscriptions */ 149 : uchar packet_subscription_live : 1; /* Want to subscribe to a stream? */ 150 : uchar packet_subscription_wait : 1; /* Request already in-flight? */ 151 : uchar bundle_subscription_live : 1; 152 : uchar bundle_subscription_wait : 1; 153 : 154 : /* Bundle state */ 155 : ulong bundle_seq; 156 : ulong bundle_txn_cnt; 157 : 158 : /* Error backoff */ 159 : fd_rng_t rng[1]; 160 : uint backoff_iter; 161 : long backoff_until; 162 : long backoff_reset; 163 : 164 : /* Stem publish */ 165 : fd_stem_context_t * stem; 166 : fd_bundle_out_ctx_t verify_out; 167 : fd_bundle_out_ctx_t plugin_out; 168 : fd_bundle_pending_txn_t * pending_txns; 169 : 170 : /* App metrics */ 171 : fd_bundle_metrics_t metrics; 172 : 173 : /* Check engine light */ 174 : uchar bundle_status_recent; /* most recently observed 'check engine light' */ 175 : uchar bundle_status_plugin; /* last 'plugin' update written */ 176 : uchar bundle_status_logged; 177 : long last_bundle_status_log_nanos; 178 : }; 179 : 180 : typedef struct fd_bundle_tile fd_bundle_tile_t; 181 : 182 : /* Define 'request_ctx' IDs to identify different types of gRPC calls */ 183 : 184 0 : #define FD_BUNDLE_CLIENT_REQ_Bundle_SubscribePackets 4 185 0 : #define FD_BUNDLE_CLIENT_REQ_Bundle_SubscribeBundles 5 186 0 : #define FD_BUNDLE_CLIENT_REQ_Bundle_GetBlockBuilderFeeInfo 6 187 : 188 : FD_PROTOTYPES_BEGIN 189 : 190 : /* fd_bundle_now is an externally linked function wrapping 191 : fd_log_wallclock. This is backed by a weak symbol, allowing tests to 192 : override the clock source. */ 193 : 194 : long 195 : fd_bundle_now( void ); 196 : 197 : /* fd_bundle_client_grpc_callbacks provides callbacks for grpc_client. */ 198 : 199 : extern fd_grpc_client_callbacks_t fd_bundle_client_grpc_callbacks; 200 : 201 : /* fd_bundle_client_step is an all-in-one routine to drive client logic. 202 : As long as the tile calls this periodically, the client will 203 : reconnect to the bundle server, authenticate, and subscribe to 204 : packets and bundles. */ 205 : 206 : void 207 : fd_bundle_client_step( fd_bundle_tile_t * bundle, 208 : int * charge_busy ); 209 : 210 : /* fd_bundle_client_step_reconnect drives the 'reconnect' state machine. 211 : Once the HTTP/2 conn is established (SETTINGS exchanged), this 212 : function drives the auth logic, requests block builder info, sets up 213 : packet and bundle subscriptions, and PINGs. */ 214 : 215 : int 216 : fd_bundle_client_step_reconnect( fd_bundle_tile_t * ctx, 217 : long now ); 218 : 219 : /* fd_bundle_tile_backoff is called whenever an error occurs. Stalls 220 : forward progress for a randomized amount of time to prevent error 221 : floods. */ 222 : 223 : void 224 : fd_bundle_tile_backoff( fd_bundle_tile_t * ctx, 225 : long now ); 226 : 227 : /* fd_bundle_tile_should_stall returns 1 if forward progress should be 228 : temporarily prevented due to an error. */ 229 : 230 : FD_FN_PURE static inline int 231 : fd_bundle_tile_should_stall( fd_bundle_tile_t const * ctx, 232 0 : long now ) { 233 0 : return now < ctx->backoff_until; 234 0 : } 235 : 236 : /* fd_bundle_tile_housekeeping runs periodically at a low frequency. */ 237 : 238 : void 239 : fd_bundle_tile_housekeeping( fd_bundle_tile_t * ctx ); 240 : 241 : /* fd_bundle_client_grpc_rx_start is the first RX callback of a stream. */ 242 : 243 : void 244 : fd_bundle_client_grpc_rx_start( 245 : void * app_ctx, 246 : ulong request_ctx 247 : ) ; 248 : 249 : /* fd_bundle_client_grpc_rx_msg is called by grpc_client when a gRPC 250 : message arrives (unary or server-streaming response). */ 251 : 252 : void 253 : fd_bundle_client_grpc_rx_msg( 254 : void * app_ctx, /* (fd_bundle_tile_t *) */ 255 : void const * protobuf, 256 : ulong protobuf_sz, 257 : ulong request_ctx /* FD_BUNDLE_CLIENT_REQ_{...} */ 258 : ); 259 : 260 : /* fd_bundle_client_grpc_rx_end is called by grpc_client when a gRPC 261 : server-streaming response finishes. */ 262 : 263 : void 264 : fd_bundle_client_grpc_rx_end( 265 : void * app_ctx, 266 : ulong request_ctx, 267 : fd_grpc_resp_hdrs_t * resp 268 : ); 269 : 270 : /* fd_bundle_client_grpc_rx_timeout is called by grpc_client when a 271 : gRPC request deadline gets exceeded. */ 272 : 273 : void 274 : fd_bundle_client_grpc_rx_timeout( 275 : void * app_ctx, 276 : ulong request_ctx, /* FD_BUNDLE_CLIENT_REQ_{...} */ 277 : int deadline_kind /* FD_GRPC_DEADLINE_{HEADER|RX_END} */ 278 : ); 279 : 280 : /* fd_bundle_client_status provides a "check engine light". 281 : 282 : Returns 0 if the client has recently failed and is currently backing 283 : off from a reconnect attempt. 284 : 285 : Returns 1 if the client is currently reconnecting. 286 : 287 : Returns 2 if all of the following conditions are met: 288 : - TCP socket is alive 289 : - SSL session is not in an error state 290 : - HTTP/2 connection is established (SETTINGS exchange done) 291 : - gRPC bundle and packet subscriptions are live 292 : - HTTP/2 PING exchange was done recently 293 : 294 : Return codes are compatible with FD_PLUGIN_MSG_BLOCK_ENGINE_UPDATE_STATUS_{...}. */ 295 : 296 : int 297 : fd_bundle_client_status( fd_bundle_tile_t const * ctx ); 298 : 299 : /* fd_bundle_request_ctx_cstr returns the gRPC method name for a 300 : FD_BUNDLE_CLIENT_REQ_* ID. Returns "unknown" the ID is not 301 : recognized. */ 302 : 303 : FD_FN_CONST char const * 304 : fd_bundle_request_ctx_cstr( ulong request_ctx ); 305 : 306 : /* fd_bundle_client_reset frees all connection-related resources. */ 307 : 308 : void 309 : fd_bundle_client_reset( fd_bundle_tile_t * ctx ); 310 : 311 : /* fd_bundle_client_ping_tx enqueues a PING frame for sending. Returns 312 : 1 on success and 0 on failure (occurs when frame_tx buf is full). */ 313 : 314 : void 315 : fd_bundle_client_send_ping( fd_bundle_tile_t * ctx ); 316 : 317 : FD_PROTOTYPES_END 318 : 319 : #endif /* HEADER_fd_src_disco_bundle_fd_bundle_tile_private_h */