Line data Source code
1 : #include "topology.h"
2 :
3 : #include "../../choreo/fd_choreo_base.h"
4 : #include "../../discof/reasm/fd_reasm.h"
5 : #include "../../discof/replay/fd_replay_notif.h"
6 : #include "../../discof/poh/fd_poh.h"
7 : #include "../../discof/replay/fd_exec.h"
8 : #include "../../discof/gossip/fd_gossip_tile.h"
9 : #include "../../discof/tower/fd_tower_tile.h"
10 : #include "../../discof/resolv/fd_resolv_tile.h"
11 : #include "../../disco/net/fd_net_tile.h"
12 : #include "../../disco/quic/fd_tpu.h"
13 : #include "../../disco/tiles.h"
14 : #include "../../disco/topo/fd_topob.h"
15 : #include "../../disco/topo/fd_cpu_topo.h"
16 : #include "../../util/pod/fd_pod_format.h"
17 : #include "../../util/tile/fd_tile_private.h"
18 : #include "../../discof/restore/utils/fd_ssmsg.h"
19 : #include "../../flamenco/runtime/fd_runtime.h"
20 : #include "../../flamenco/gossip/fd_gossip.h"
21 : #include "../../flamenco/runtime/context/fd_capture_ctx.h"
22 :
23 : #include <sys/random.h>
24 : #include <sys/types.h>
25 : #include <sys/socket.h>
26 : #include <netdb.h>
27 :
28 : extern fd_topo_obj_callbacks_t * CALLBACKS[];
29 :
30 : static void
31 0 : parse_ip_port( const char * name, const char * ip_port, fd_topo_ip_port_t *parsed_ip_port) {
32 0 : char buf[ sizeof( "255.255.255.255:65536" ) ];
33 0 : memcpy( buf, ip_port, sizeof( buf ) );
34 0 : char *ip_end = strchr( buf, ':' );
35 0 : if( FD_UNLIKELY( !ip_end ) )
36 0 : FD_LOG_ERR(( "[%s] must in the form ip:port", name ));
37 0 : *ip_end = '\0';
38 :
39 0 : if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( buf, &( parsed_ip_port->ip ) ) ) ) {
40 0 : FD_LOG_ERR(( "could not parse IP %s in [%s]", buf, name ));
41 0 : }
42 :
43 0 : parsed_ip_port->port = fd_cstr_to_ushort( ip_end+1 );
44 0 : if( FD_UNLIKELY( !parsed_ip_port->port ) )
45 0 : FD_LOG_ERR(( "could not parse port %s in [%s]", ip_end+1, name ));
46 0 : }
47 :
48 : fd_topo_obj_t *
49 3 : setup_topo_bank_hash_cmp( fd_topo_t * topo, char const * wksp_name ) {
50 3 : fd_topo_obj_t * obj = fd_topob_obj( topo, "bh_cmp", wksp_name );
51 3 : return obj;
52 3 : }
53 :
54 : fd_topo_obj_t *
55 : setup_topo_banks( fd_topo_t * topo,
56 : char const * wksp_name,
57 : ulong max_total_banks,
58 3 : ulong max_fork_width ) {
59 3 : fd_topo_obj_t * obj = fd_topob_obj( topo, "banks", wksp_name );
60 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, max_total_banks, "obj.%lu.max_total_banks", obj->id ) );
61 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, max_fork_width, "obj.%lu.max_fork_width", obj->id ) );
62 3 : return obj;
63 3 : }
64 :
65 : static fd_topo_obj_t *
66 3 : setup_topo_fec_sets( fd_topo_t * topo, char const * wksp_name, ulong sz ) {
67 3 : fd_topo_obj_t * obj = fd_topob_obj( topo, "fec_sets", wksp_name );
68 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, sz, "obj.%lu.sz", obj->id ) );
69 3 : return obj;
70 3 : }
71 :
72 : fd_topo_obj_t *
73 : setup_topo_funk( fd_topo_t * topo,
74 : char const * wksp_name,
75 : ulong max_account_records,
76 : ulong max_database_transactions,
77 : ulong heap_size_gib,
78 3 : int lock_pages ) {
79 3 : fd_topo_obj_t * obj = fd_topob_obj( topo, "funk", wksp_name );
80 3 : FD_TEST( fd_pod_insert_ulong( topo->props, "funk", obj->id ) );
81 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, max_account_records, "obj.%lu.rec_max", obj->id ) );
82 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, max_database_transactions, "obj.%lu.txn_max", obj->id ) );
83 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, heap_size_gib*(1UL<<30), "obj.%lu.heap_max", obj->id ) );
84 3 : ulong funk_footprint = fd_funk_footprint( max_database_transactions, max_account_records );
85 3 : if( FD_UNLIKELY( !funk_footprint ) ) FD_LOG_ERR(( "Invalid [funk] parameters" ));
86 :
87 : /* Increase workspace partition count */
88 3 : ulong wksp_idx = fd_topo_find_wksp( topo, wksp_name );
89 3 : FD_TEST( wksp_idx!=ULONG_MAX );
90 3 : fd_topo_wksp_t * wksp = &topo->workspaces[ wksp_idx ];
91 3 : ulong part_max = fd_wksp_part_max_est( funk_footprint+(heap_size_gib*(1UL<<30)), 1U<<14U );
92 3 : if( FD_UNLIKELY( !part_max ) ) FD_LOG_ERR(( "fd_wksp_part_max_est(%lu,16KiB) failed", funk_footprint ));
93 3 : wksp->part_max += part_max;
94 3 : wksp->is_locked = lock_pages;
95 :
96 3 : return obj;
97 3 : }
98 :
99 : fd_topo_obj_t *
100 : setup_topo_store( fd_topo_t * topo,
101 : char const * wksp_name,
102 : ulong fec_max,
103 3 : uint part_cnt ) {
104 3 : fd_topo_obj_t * obj = fd_topob_obj( topo, "store", wksp_name );
105 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, fec_max, "obj.%lu.fec_max", obj->id ) );
106 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, part_cnt, "obj.%lu.part_cnt", obj->id ) );
107 3 : return obj;
108 3 : }
109 :
110 : fd_topo_obj_t *
111 : setup_topo_txncache( fd_topo_t * topo,
112 : char const * wksp_name,
113 : ulong max_rooted_slots,
114 : ulong max_live_slots,
115 3 : ulong max_txn_per_slot ) {
116 3 : fd_topo_obj_t * obj = fd_topob_obj( topo, "txncache", wksp_name );
117 :
118 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, max_rooted_slots, "obj.%lu.max_rooted_slots", obj->id ) );
119 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, max_live_slots, "obj.%lu.max_live_slots", obj->id ) );
120 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, max_txn_per_slot, "obj.%lu.max_txn_per_slot", obj->id ) );
121 :
122 3 : return obj;
123 3 : }
124 :
125 : static int
126 : resolve_address( char const * address,
127 0 : uint * ip_addr ) {
128 0 : struct addrinfo hints = { .ai_family = AF_INET };
129 0 : struct addrinfo * res;
130 0 : int err = getaddrinfo( address, NULL, &hints, &res );
131 0 : if( FD_UNLIKELY( err ) ) {
132 0 : FD_LOG_WARNING(( "cannot resolve address \"%s\": %i-%s", address, err, gai_strerror( err ) ));
133 0 : return 0;
134 0 : }
135 :
136 0 : int resolved = 0;
137 0 : for( struct addrinfo * cur=res; cur; cur=cur->ai_next ) {
138 0 : if( FD_UNLIKELY( cur->ai_addr->sa_family!=AF_INET ) ) continue;
139 0 : struct sockaddr_in const * addr = (struct sockaddr_in const *)cur->ai_addr;
140 0 : *ip_addr = addr->sin_addr.s_addr;
141 0 : resolved = 1;
142 0 : break;
143 0 : }
144 :
145 0 : freeaddrinfo( res );
146 0 : return resolved;
147 0 : }
148 :
149 : static int
150 : resolve_peer( char const * peer,
151 0 : fd_ip4_port_t * ip4_port ) {
152 :
153 : /* Split host:port */
154 0 : char const * host_port = peer;
155 0 : if( FD_LIKELY( strncmp( peer, "http://", 7UL )==0 ) ) {
156 0 : host_port += 7UL;
157 0 : } else if( FD_LIKELY( strncmp( peer, "https://", 8UL )==0 ) ) {
158 0 : host_port += 8UL;
159 0 : }
160 :
161 0 : char const * colon = strrchr( host_port, ':' );
162 0 : if( FD_UNLIKELY( !colon ) ) {
163 0 : FD_LOG_ERR(( "invalid [gossip.entrypoints] entry \"%s\": no port number", host_port ));
164 0 : }
165 :
166 0 : char fqdn[ 255 ];
167 0 : ulong fqdn_len = (ulong)( colon-host_port );
168 0 : if( FD_UNLIKELY( fqdn_len>254 ) ) {
169 0 : FD_LOG_ERR(( "invalid [gossip.entrypoints] entry \"%s\": hostname too long", host_port ));
170 0 : }
171 0 : fd_memcpy( fqdn, host_port, fqdn_len );
172 0 : fqdn[ fqdn_len ] = '\0';
173 :
174 : /* Parse port number */
175 :
176 0 : char const * port_str = colon+1;
177 0 : char const * endptr = NULL;
178 0 : ulong port = strtoul( port_str, (char **)&endptr, 10 );
179 0 : if( FD_UNLIKELY( !endptr || !port || port>USHORT_MAX || *endptr!='\0' ) ) {
180 0 : FD_LOG_ERR(( "invalid [gossip.entrypoints] entry \"%s\": invalid port number", host_port ));
181 0 : }
182 0 : ip4_port->port = (ushort)fd_ushort_bswap( (ushort)port );
183 :
184 : /* Resolve hostname */
185 0 : int resolved = resolve_address( fqdn, &ip4_port->addr );
186 0 : return resolved;
187 0 : }
188 :
189 : static void
190 3 : resolve_gossip_entrypoints( config_t * config ) {
191 3 : ulong entrypoint_cnt = config->gossip.entrypoints_cnt;
192 3 : for( ulong i=0UL; i<entrypoint_cnt; i++ ) {
193 0 : if( FD_UNLIKELY( 0==resolve_peer( config->gossip.entrypoints[ i ], &config->gossip.resolved_entrypoints[ i ] ) ) ) {
194 0 : FD_LOG_ERR(( "failed to resolve address of [gossip.entrypoints] entry \"%s\"", config->gossip.entrypoints[ i ] ));
195 0 : }
196 0 : }
197 3 : }
198 :
199 : void
200 3 : fd_topo_initialize( config_t * config ) {
201 : /* TODO: Not here ... */
202 3 : resolve_gossip_entrypoints( config );
203 :
204 3 : ulong net_tile_cnt = config->layout.net_tile_count;
205 3 : ulong shred_tile_cnt = config->layout.shred_tile_count;
206 3 : ulong quic_tile_cnt = config->layout.quic_tile_count;
207 3 : ulong verify_tile_cnt = config->layout.verify_tile_count;
208 3 : ulong resolv_tile_cnt = config->layout.resolv_tile_count;
209 3 : ulong bank_tile_cnt = config->layout.bank_tile_count;
210 :
211 3 : ulong gossvf_tile_cnt = config->firedancer.layout.gossvf_tile_count;
212 3 : ulong exec_tile_cnt = config->firedancer.layout.exec_tile_count;
213 3 : ulong writer_tile_cnt = config->firedancer.layout.writer_tile_count;
214 3 : ulong sign_tile_cnt = config->firedancer.layout.sign_tile_count;
215 :
216 3 : int snapshots_enabled = !!config->gossip.entrypoints_cnt;
217 3 : int solcap_enabled = strcmp( "", config->capture.solcap_capture );
218 :
219 3 : fd_topo_t * topo = fd_topob_new( &config->topo, config->name );
220 :
221 3 : topo->max_page_size = fd_cstr_to_shmem_page_sz( config->hugetlbfs.max_page_size );
222 3 : topo->gigantic_page_threshold = config->hugetlbfs.gigantic_page_threshold_mib << 20;
223 :
224 : /* topo, name */
225 3 : fd_topob_wksp( topo, "metric" );
226 3 : fd_topob_wksp( topo, "genesi" );
227 3 : fd_topob_wksp( topo, "ipecho" );
228 3 : fd_topob_wksp( topo, "gossvf" );
229 3 : fd_topob_wksp( topo, "gossip" );
230 3 : fd_topob_wksp( topo, "shred" );
231 3 : fd_topob_wksp( topo, "repair" );
232 3 : fd_topob_wksp( topo, "replay" );
233 3 : fd_topob_wksp( topo, "exec" );
234 3 : fd_topob_wksp( topo, "writer" );
235 3 : fd_topob_wksp( topo, "tower" );
236 3 : fd_topob_wksp( topo, "send" );
237 :
238 3 : fd_topob_wksp( topo, "quic" );
239 3 : fd_topob_wksp( topo, "verify" );
240 3 : fd_topob_wksp( topo, "dedup" );
241 3 : fd_topob_wksp( topo, "resolv" );
242 3 : fd_topob_wksp( topo, "pack" );
243 3 : fd_topob_wksp( topo, "bank" );
244 3 : fd_topob_wksp( topo, "poh" );
245 3 : fd_topob_wksp( topo, "sign" );
246 :
247 3 : fd_topob_wksp( topo, "metric_in" );
248 :
249 3 : fd_topob_wksp( topo, "net_gossip" );
250 3 : fd_topob_wksp( topo, "net_shred" );
251 3 : fd_topob_wksp( topo, "net_repair" );
252 3 : fd_topob_wksp( topo, "net_send" );
253 3 : fd_topob_wksp( topo, "net_quic" );
254 :
255 3 : fd_topob_wksp( topo, "genesi_out" );
256 3 : fd_topob_wksp( topo, "ipecho_out" );
257 3 : fd_topob_wksp( topo, "gossvf_gossi" );
258 3 : fd_topob_wksp( topo, "gossip_gossv" );
259 3 : fd_topob_wksp( topo, "gossip_out" );
260 :
261 3 : fd_topob_wksp( topo, "shred_repair" );
262 3 : fd_topob_wksp( topo, "repair_repla" );
263 3 : fd_topob_wksp( topo, "replay_pack" );
264 3 : fd_topob_wksp( topo, "replay_stake" );
265 3 : fd_topob_wksp( topo, "replay_exec" );
266 3 : fd_topob_wksp( topo, "replay_tower" );
267 3 : fd_topob_wksp( topo, "exec_writer" );
268 3 : fd_topob_wksp( topo, "tower_out" );
269 3 : fd_topob_wksp( topo, "send_txns" ); /* TODO: Badly named. Rename to indicate tiles */
270 :
271 3 : fd_topob_wksp( topo, "quic_verify" );
272 3 : fd_topob_wksp( topo, "verify_dedup" );
273 3 : fd_topob_wksp( topo, "dedup_resolv" );
274 3 : fd_topob_wksp( topo, "resolv_pack" );
275 3 : fd_topob_wksp( topo, "pack_poh" );
276 3 : fd_topob_wksp( topo, "pack_bank" );
277 3 : fd_topob_wksp( topo, "replay_resol" );
278 3 : fd_topob_wksp( topo, "resolv_repla" );
279 3 : fd_topob_wksp( topo, "bank_pack" );
280 3 : fd_topob_wksp( topo, "bank_poh" );
281 3 : fd_topob_wksp( topo, "bank_busy" );
282 3 : fd_topob_wksp( topo, "poh_shred" );
283 3 : fd_topob_wksp( topo, "poh_replay" );
284 :
285 : /* TODO: WTF are these for? */
286 3 : fd_topob_wksp( topo, "funk" );
287 3 : fd_topob_wksp( topo, "bh_cmp" );
288 3 : fd_topob_wksp( topo, "fec_sets" );
289 3 : fd_topob_wksp( topo, "tcache" ); /* TODO: Rename txncache */
290 3 : fd_topob_wksp( topo, "exec_spad" );
291 3 : fd_topob_wksp( topo, "banks" );
292 3 : fd_topob_wksp( topo, "store" );
293 3 : fd_topob_wksp( topo, "executed_txn" );
294 :
295 3 : fd_topob_wksp( topo, "gossip_sign" );
296 3 : fd_topob_wksp( topo, "sign_gossip" );
297 :
298 3 : fd_topob_wksp( topo, "shred_sign" );
299 3 : fd_topob_wksp( topo, "sign_shred" );
300 :
301 3 : fd_topob_wksp( topo, "repair_sign" );
302 3 : fd_topob_wksp( topo, "sign_repair" );
303 :
304 3 : fd_topob_wksp( topo, "send_sign" );
305 3 : fd_topob_wksp( topo, "sign_send" );
306 :
307 3 : if( FD_LIKELY( snapshots_enabled ) ) {
308 0 : fd_topob_wksp( topo, "snapdc" );
309 0 : fd_topob_wksp( topo, "snaprd" );
310 0 : fd_topob_wksp( topo, "snapin" );
311 :
312 0 : fd_topob_wksp( topo, "snapdc_rd" );
313 0 : fd_topob_wksp( topo, "snapin_rd" );
314 0 : fd_topob_wksp( topo, "snap_stream" ); /* TODO: Rename ... */
315 0 : fd_topob_wksp( topo, "snap_zstd" ); /* TODO: Rename ... */
316 0 : fd_topob_wksp( topo, "snap_out" ); /* TODO: Rename ... */
317 0 : }
318 :
319 840 : #define FOR(cnt) for( ulong i=0UL; i<cnt; i++ )
320 :
321 : /* TODO: Explain this .... USHORT_MAX is not dcache max */
322 3 : ulong pending_fec_shreds_depth = fd_ulong_min( fd_ulong_pow2_up( config->tiles.shred.max_pending_shred_sets * FD_REEDSOL_DATA_SHREDS_MAX ), USHORT_MAX + 1 /* dcache max */ );
323 :
324 : /* topo, link_name, wksp_name, depth, mtu, burst */
325 3 : /**/ fd_topob_link( topo, "gossip_net", "net_gossip", config->net.ingress_buffer_size, FD_NET_MTU, 1UL );
326 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "shred_net", "net_shred", config->net.ingress_buffer_size, FD_NET_MTU, 1UL );
327 3 : /**/ fd_topob_link( topo, "repair_net", "net_repair", config->net.ingress_buffer_size, FD_NET_MTU, 1UL );
328 3 : /**/ fd_topob_link( topo, "send_net", "net_send", config->net.ingress_buffer_size, FD_NET_MTU, 2UL ); /* TODO: 2 is probably not correct, should be 1 */
329 3 : FOR(quic_tile_cnt) fd_topob_link( topo, "quic_net", "net_quic", config->net.ingress_buffer_size, FD_NET_MTU, 1UL );
330 :
331 3 : if( FD_LIKELY( snapshots_enabled ) ) {
332 0 : /**/ fd_topob_link( topo, "snap_zstd", "snap_zstd", 8192UL, 16384UL, 1UL ); /* TODO: Rename */
333 0 : /**/ fd_topob_link( topo, "snap_stream", "snap_stream", 2048UL, USHORT_MAX, 1UL ); /* TODO: Rename */
334 0 : /**/ fd_topob_link( topo, "snap_out", "snap_out", 2UL, sizeof(fd_snapshot_manifest_t), 1UL ); /* TODO: Rename */
335 0 : /**/ fd_topob_link( topo, "snapdc_rd", "snapdc_rd", 128UL, 0UL, 1UL );
336 0 : /**/ fd_topob_link( topo, "snapin_rd", "snapin_rd", 128UL, 0UL, 1UL );
337 0 : }
338 :
339 : /**/ fd_topob_link( topo, "genesi_out", "genesi_out", 2UL, 10UL*1024UL*1024UL+32UL+sizeof(fd_lthash_value_t), 1UL );
340 3 : /**/ fd_topob_link( topo, "ipecho_out", "ipecho_out", 2UL, 0UL, 1UL );
341 3 : FOR(gossvf_tile_cnt) fd_topob_link( topo, "gossvf_gossi", "gossvf_gossi", config->net.ingress_buffer_size, sizeof(fd_gossip_view_t)+FD_NET_MTU, 1UL );
342 3 : /**/ fd_topob_link( topo, "gossip_gossv", "gossip_gossv", 65536UL*4UL, sizeof(fd_gossip_ping_update_t), 1UL ); /* TODO: Unclear where this depth comes from ... fix */
343 3 : /**/ fd_topob_link( topo, "gossip_out", "gossip_out", 65536UL*4UL, sizeof(fd_gossip_update_message_t), 1UL ); /* TODO: Unclear where this depth comes from ... fix */
344 :
345 3 : FOR(quic_tile_cnt) fd_topob_link( topo, "quic_verify", "quic_verify", config->tiles.verify.receive_buffer_size, FD_TPU_REASM_MTU, config->tiles.quic.txn_reassembly_count );
346 18 : FOR(verify_tile_cnt) fd_topob_link( topo, "verify_dedup", "verify_dedup", config->tiles.verify.receive_buffer_size, FD_TPU_PARSED_MTU, 1UL );
347 3 : /**/ fd_topob_link( topo, "dedup_resolv", "dedup_resolv", 65536UL, FD_TPU_PARSED_MTU, 1UL );
348 3 : FOR(resolv_tile_cnt) fd_topob_link( topo, "resolv_pack", "resolv_pack", 65536UL, FD_TPU_RESOLVED_MTU, 1UL );
349 3 : /**/ fd_topob_link( topo, "replay_pack", "replay_pack", 128UL, sizeof(fd_became_leader_t), 1UL ); /* TODO: Depth probably doesn't need to be 128 */
350 3 : /**/ fd_topob_link( topo, "replay_stake", "replay_stake", 128UL, FD_STAKE_OUT_MTU, 1UL ); /* TODO: Depth probably doesn't need to be 128 */
351 3 : /**/ fd_topob_link( topo, "pack_poh", "pack_poh", 128UL, sizeof(fd_done_packing_t), 1UL );
352 : /* pack_bank is shared across all banks, so if one bank stalls due to complex transactions, the buffer neeeds to be large so that
353 : other banks can keep proceeding. */
354 3 : /**/ fd_topob_link( topo, "pack_bank", "pack_bank", 65536UL, USHORT_MAX, 1UL );
355 3 : FOR(bank_tile_cnt) fd_topob_link( topo, "bank_poh", "bank_poh", 16384UL, USHORT_MAX, 1UL );
356 3 : FOR(bank_tile_cnt) fd_topob_link( topo, "bank_pack", "bank_pack", 16384UL, USHORT_MAX, 1UL );
357 3 : /**/ fd_topob_link( topo, "poh_shred", "poh_shred", 16384UL, USHORT_MAX, 1UL );
358 3 : /**/ fd_topob_link( topo, "poh_replay", "poh_replay", 128UL, sizeof(fd_poh_leader_slot_ended_t), 1UL ); /* TODO: Depth probably doesn't need to be 128 */
359 3 : /**/ fd_topob_link( topo, "replay_resol", "replay_resol", 128UL, sizeof(fd_resov_completed_slot_t), 1UL );
360 3 : FOR(resolv_tile_cnt) fd_topob_link( topo, "resolv_repla", "resolv_repla", 128UL, sizeof(fd_resolv_slot_exchanged_t), 1UL );
361 3 : /**/ fd_topob_link( topo, "executed_txn", "executed_txn", 16384UL, 64UL, 1UL ); /* TODO: Rename this ... */
362 :
363 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "shred_sign", "shred_sign", 128UL, 32UL, 1UL );
364 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "sign_shred", "sign_shred", 128UL, sizeof(fd_ed25519_sig_t), 1UL );
365 :
366 : /**/ fd_topob_link( topo, "gossip_sign", "gossip_sign", 128UL, 2048UL, 1UL ); /* TODO: Where does 2048 come from? Depth probably doesn't need to be 128 */
367 3 : /**/ fd_topob_link( topo, "sign_gossip", "sign_gossip", 128UL, sizeof(fd_ed25519_sig_t), 1UL ); /* TODO: Depth probably doesn't need to be 128 */
368 :
369 3 : FOR(sign_tile_cnt-1) fd_topob_link( topo, "repair_sign", "repair_sign", 128UL, 2048UL, 1UL ); /* TODO: Where does 2048 come from? Depth probably doesn't need to be 128 */
370 3 : FOR(sign_tile_cnt-1) fd_topob_link( topo, "sign_repair", "sign_repair", 1024UL, sizeof(fd_ed25519_sig_t), 1UL ); /* TODO: WTF is this depth? It should match repair_sign */
371 3 : /**/ fd_topob_link( topo, "ping_sign", "repair_sign", 128UL, 2048UL, 1UL ); /* TODO: Huh? Why is this a different link? Where does 2048 come from? Depth not 128 */
372 3 : /**/ fd_topob_link( topo, "sign_ping", "sign_repair", 128UL, sizeof(fd_ed25519_sig_t), 1UL ); /* TODO: What is this link ... ? Why separate, doesn't make sense */
373 :
374 3 : /**/ fd_topob_link( topo, "send_sign", "send_sign", 128UL, FD_TXN_MTU, 1UL ); /* TODO: Depth probably doesn't need to be 128 */
375 3 : /**/ fd_topob_link( topo, "sign_send", "sign_send", 128UL, sizeof(fd_ed25519_sig_t), 1UL ); /* TODO: Depth probably doesn't need to be 128 */
376 :
377 3 : /**/ fd_topob_link( topo, "repair_repla", "repair_repla", 65536UL, sizeof(fd_reasm_fec_t), 1UL );
378 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "shred_repair", "shred_repair", pending_fec_shreds_depth, FD_SHRED_REPAIR_MTU, 3UL ); /* TODO: Pretty sure burst of 3 is incorrect here */
379 3 : FOR(shred_tile_cnt) fd_topob_link( topo, "repair_shred", "shred_repair", pending_fec_shreds_depth, sizeof(fd_ed25519_sig_t), 1UL ); /* TODO: Also pending_fec_shreds_depth? Seems wrong */
380 3 : /**/ fd_topob_link( topo, "replay_tower", "replay_tower", fd_ulong_pow2_up( config->firedancer.runtime.max_total_banks*FD_REPLAY_TOWER_VOTE_ACC_MAX ), sizeof(fd_replay_tower_t), 1UL ); /* TODO: Don't think this depth makes much sense? This is weirdly outsized for a vote link */
381 3 : /**/ fd_topob_link( topo, "tower_out", "tower_out", 1024UL, sizeof(fd_tower_slot_done_t), 1UL );
382 3 : /**/ fd_topob_link( topo, "send_txns", "send_txns", 128UL, FD_TPU_RAW_MTU, 1UL ); /* TODO: Horribly named. Rename to indicate tile and where its going */
383 :
384 24 : FOR(exec_tile_cnt) fd_topob_link( topo, "replay_exec", "replay_exec", 128UL, 10240UL, exec_tile_cnt ); /* TODO: Depth probably not 128. MTU is made up and needs to be sized correctly. */
385 : /* Assuming the number of writer tiles is sufficient to keep up with
386 : the number of exec tiles, under equilibrium, we should have at least
387 : enough link space to buffer worst case input shuffling done by the
388 : stem. That is, when a link is so unlucky, that the stem RNG decided
389 : to process every other link except this one, for all writer tiles.
390 : This would be fd_ulong_pow2_up( exec_tile_cnt*writer_tile_cnt+1UL ).
391 :
392 : This is all assuming we have true pipelining between exec and writer
393 : tiles. Right now, we don't. So in reality there can be at most 1
394 : in-flight transaction per exec tile, and hence a depth of 1 is in
395 : theory sufficient for each exec_writer link. */
396 24 : FOR(exec_tile_cnt) fd_topob_link( topo, "exec_writer", "exec_writer", 128UL, FD_EXEC_WRITER_MTU, 1UL ); /* TODO: Update depth to reflect comment. */
397 :
398 3 : ushort parsed_tile_to_cpu[ FD_TILE_MAX ];
399 : /* Unassigned tiles will be floating, unless auto topology is enabled. */
400 3075 : for( ulong i=0UL; i<FD_TILE_MAX; i++ ) parsed_tile_to_cpu[ i ] = USHORT_MAX;
401 :
402 3 : int is_auto_affinity = !strcmp( config->layout.affinity, "auto" );
403 :
404 3 : fd_topo_cpus_t cpus[1];
405 3 : fd_topo_cpus_init( cpus );
406 :
407 3 : ulong affinity_tile_cnt = 0UL;
408 3 : if( FD_LIKELY( !is_auto_affinity ) ) affinity_tile_cnt = fd_tile_private_cpus_parse( config->layout.affinity, parsed_tile_to_cpu );
409 :
410 3 : ulong tile_to_cpu[ FD_TILE_MAX ] = {0};
411 3 : for( ulong i=0UL; i<affinity_tile_cnt; i++ ) {
412 0 : if( FD_UNLIKELY( parsed_tile_to_cpu[ i ]!=USHORT_MAX && parsed_tile_to_cpu[ i ]>=cpus->cpu_cnt ) )
413 0 : FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.affinity] specifies a CPU index of %hu, but the system "
414 0 : "only has %lu CPUs. You should either change the CPU allocations in the affinity string, or increase the number of CPUs "
415 0 : "in the system.",
416 0 : parsed_tile_to_cpu[ i ], cpus->cpu_cnt ));
417 0 : tile_to_cpu[ i ] = fd_ulong_if( parsed_tile_to_cpu[ i ]==USHORT_MAX, ULONG_MAX, (ulong)parsed_tile_to_cpu[ i ] );
418 0 : }
419 :
420 3 : fd_topos_net_tiles( topo, net_tile_cnt, &config->net, config->tiles.netlink.max_routes, config->tiles.netlink.max_peer_routes, config->tiles.netlink.max_neighbors, tile_to_cpu );
421 :
422 3 : FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_gossvf", i, config->net.ingress_buffer_size );
423 3 : FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_shred", i, config->net.ingress_buffer_size );
424 3 : FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_repair", i, config->net.ingress_buffer_size );
425 3 : FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_send", i, config->net.ingress_buffer_size );
426 3 : FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_quic", i, config->net.ingress_buffer_size );
427 :
428 : /* topo, tile_name, tile_wksp, metrics_wksp, cpu_idx, is_agave, uses_keyswitch */
429 : /**/ fd_topob_tile( topo, "metric", "metric", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
430 :
431 3 : if( FD_LIKELY( snapshots_enabled ) ) {
432 0 : fd_topob_tile( topo, "snaprd", "snaprd", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 )->allow_shutdown = 1;
433 0 : fd_topob_tile( topo, "snapdc", "snapdc", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 )->allow_shutdown = 1;
434 0 : fd_topob_tile( topo, "snapin", "snapin", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 )->allow_shutdown = 1;
435 0 : }
436 :
437 : /**/ fd_topob_tile( topo, "genesi", "genesi", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 )->allow_shutdown = 1;
438 3 : /**/ fd_topob_tile( topo, "ipecho", "ipecho", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
439 3 : FOR(gossvf_tile_cnt) fd_topob_tile( topo, "gossvf", "gossvf", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
440 3 : /**/ fd_topob_tile( topo, "gossip", "gossip", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
441 :
442 3 : FOR(shred_tile_cnt) fd_topob_tile( topo, "shred", "shred", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
443 3 : /**/ fd_topob_tile( topo, "repair", "repair", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 ); /* TODO: Wrong? Needs to use keyswitch as signs */
444 3 : /**/ fd_topob_tile( topo, "replay", "replay", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
445 24 : FOR(exec_tile_cnt) fd_topob_tile( topo, "exec", "exec", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
446 3 : FOR(writer_tile_cnt) fd_topob_tile( topo, "writer", "writer", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
447 3 : /**/ fd_topob_tile( topo, "tower", "tower", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
448 3 : /**/ fd_topob_tile( topo, "send", "send", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
449 :
450 3 : FOR(quic_tile_cnt) fd_topob_tile( topo, "quic", "quic", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
451 18 : FOR(verify_tile_cnt) fd_topob_tile( topo, "verify", "verify", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
452 3 : /**/ fd_topob_tile( topo, "dedup", "dedup", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
453 3 : FOR(resolv_tile_cnt) fd_topob_tile( topo, "resolv", "resolv", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
454 3 : FOR(resolv_tile_cnt) strncpy( topo->tiles[ topo->tile_cnt-1UL-i ].metrics_name, "resolf", 8UL );
455 3 : /**/ fd_topob_tile( topo, "pack", "pack", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, config->tiles.bundle.enabled );
456 3 : FOR(bank_tile_cnt) fd_topob_tile( topo, "bank", "bank", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
457 3 : FOR(bank_tile_cnt) strncpy( topo->tiles[ topo->tile_cnt-1UL-i ].metrics_name, "bankf", 6UL );
458 3 : /**/ fd_topob_tile( topo, "poh", "poh", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
459 6 : FOR(sign_tile_cnt) fd_topob_tile( topo, "sign", "sign", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
460 :
461 : /* topo, tile_name, tile_kind_id, fseq_wksp, link_name, link_kind_id, reliable, polled */
462 6 : FOR(gossvf_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
463 3 : fd_topob_tile_in( topo, "gossvf", i, "metric_in", "net_gossvf", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
464 6 : FOR(shred_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
465 3 : fd_topob_tile_in ( topo, "shred", i, "metric_in", "net_shred", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
466 3 : FOR(net_tile_cnt) fd_topob_tile_in( topo, "repair", 0UL, "metric_in", "net_repair", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
467 3 : /**/ fd_topob_tile_out( topo, "repair", 0UL, "repair_net", 0UL );
468 3 : /**/ fd_topob_tile_in ( topo, "send", 0UL, "metric_in", "net_send", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
469 6 : FOR(quic_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
470 3 : fd_topob_tile_in( topo, "quic", i, "metric_in", "net_quic", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
471 :
472 3 : FOR(shred_tile_cnt) fd_topos_tile_in_net( topo, "metric_in", "shred_net", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
473 3 : /**/ fd_topos_tile_in_net( topo, "metric_in", "gossip_net", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
474 3 : /**/ fd_topos_tile_in_net( topo, "metric_in", "repair_net", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
475 3 : /**/ fd_topos_tile_in_net( topo, "metric_in", "send_net", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
476 3 : FOR(quic_tile_cnt) fd_topos_tile_in_net( topo, "metric_in", "quic_net", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
477 :
478 3 : /**/ fd_topob_tile_out( topo, "genesi", 0UL, "genesi_out", 0UL );
479 3 : /**/ fd_topob_tile_in ( topo, "ipecho", 0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
480 3 : /**/ fd_topob_tile_out( topo, "ipecho", 0UL, "ipecho_out", 0UL );
481 :
482 3 : FOR(gossvf_tile_cnt) fd_topob_tile_out( topo, "gossvf", i, "gossvf_gossi", i );
483 3 : FOR(gossvf_tile_cnt) fd_topob_tile_in ( topo, "gossvf", i, "metric_in", "gossip_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
484 3 : FOR(gossvf_tile_cnt) fd_topob_tile_in ( topo, "gossvf", i, "metric_in", "gossip_gossv", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
485 3 : FOR(gossvf_tile_cnt) fd_topob_tile_in ( topo, "gossvf", i, "metric_in", "ipecho_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
486 3 : FOR(gossvf_tile_cnt) fd_topob_tile_in ( topo, "gossvf", i, "metric_in", "replay_stake", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
487 3 : /**/ fd_topob_tile_in ( topo, "gossip", 0UL, "metric_in", "replay_stake", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
488 3 : /**/ fd_topob_tile_out( topo, "gossip", 0UL, "gossip_out", 0UL );
489 3 : /**/ fd_topob_tile_out( topo, "gossip", 0UL, "gossip_net", 0UL );
490 3 : /**/ fd_topob_tile_in ( topo, "gossip", 0UL, "metric_in", "ipecho_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
491 3 : FOR(gossvf_tile_cnt) fd_topob_tile_in ( topo, "gossip", 0UL, "metric_in", "gossvf_gossi", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
492 3 : /**/ fd_topob_tile_in( topo, "gossip", 0UL, "metric_in", "send_txns", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
493 3 : /**/ fd_topob_tile_out( topo, "gossip", 0UL, "gossip_gossv", 0UL );
494 :
495 3 : if( FD_LIKELY( snapshots_enabled ) ) {
496 0 : fd_topob_tile_in( topo, "snaprd", 0UL, "metric_in", "gossip_out", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* TODO: Fix backpressure issues and change this back to reliable. */
497 0 : fd_topob_tile_out( topo, "snaprd", 0UL, "snap_zstd", 0UL );
498 0 : fd_topob_tile_in ( topo, "snaprd", 0UL, "metric_in", "snapdc_rd", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
499 0 : fd_topob_tile_in ( topo, "snaprd", 0UL, "metric_in", "snapin_rd", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
500 0 : fd_topob_tile_in ( topo, "snapdc", 0UL, "metric_in", "snap_zstd", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
501 0 : fd_topob_tile_out( topo, "snapdc", 0UL, "snap_stream", 0UL );
502 0 : fd_topob_tile_out( topo, "snapdc", 0UL, "snapdc_rd", 0UL );
503 0 : fd_topob_tile_in ( topo, "snapin", 0UL, "metric_in", "snap_stream", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
504 0 : fd_topob_tile_out( topo, "snapin", 0UL, "snap_out", 0UL );
505 0 : fd_topob_tile_out( topo, "snapin", 0UL, "snapin_rd", 0UL );
506 0 : fd_topob_tile_in ( topo, "replay", 0UL, "metric_in", "snap_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
507 0 : }
508 :
509 3 : /**/ fd_topob_tile_in( topo, "repair", 0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
510 3 : /**/ fd_topob_tile_in( topo, "repair", 0UL, "metric_in", "gossip_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
511 3 : /**/ fd_topob_tile_in( topo, "repair", 0UL, "metric_in", "tower_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
512 3 : /**/ fd_topob_tile_in( topo, "repair", 0UL, "metric_in", "replay_stake", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
513 3 : if( snapshots_enabled ) {
514 0 : fd_topob_tile_in( topo, "repair", 0UL, "metric_in", "snap_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
515 0 : }
516 3 : FOR(shred_tile_cnt) fd_topob_tile_in( topo, "repair", 0UL, "metric_in", "shred_repair", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
517 3 : /**/ fd_topob_tile_out( topo, "repair", 0UL, "repair_repla", 0UL );
518 3 : FOR(shred_tile_cnt) fd_topob_tile_out( topo, "repair", 0UL, "repair_shred", i );
519 3 : /**/ fd_topob_tile_in ( topo, "replay", 0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
520 3 : /**/ fd_topob_tile_in ( topo, "replay", 0UL, "metric_in", "repair_repla", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
521 3 : /**/ fd_topob_tile_out( topo, "replay", 0UL, "replay_stake", 0UL );
522 3 : /**/ fd_topob_tile_out( topo, "replay", 0UL, "replay_resol", 0UL );
523 3 : /**/ fd_topob_tile_out( topo, "replay", 0UL, "executed_txn", 0UL );
524 3 : /**/ fd_topob_tile_out( topo, "replay", 0UL, "replay_pack", 0UL );
525 24 : FOR(exec_tile_cnt) fd_topob_tile_out( topo, "replay", 0UL, "replay_exec", i );
526 3 : /**/ fd_topob_tile_out( topo, "replay", 0UL, "replay_tower", 0UL );
527 3 : /**/ fd_topob_tile_in ( topo, "replay", 0UL, "metric_in", "tower_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
528 3 : FOR(resolv_tile_cnt) fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "resolv_repla", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
529 :
530 3 : /**/ fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "poh_replay", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
531 24 : FOR(exec_tile_cnt) fd_topob_tile_in( topo, "exec", i, "metric_in", "replay_exec", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
532 24 : FOR(exec_tile_cnt) fd_topob_tile_out( topo, "exec", i, "exec_writer", i );
533 : /* All writer tiles read from all exec tiles. Each exec tile has a
534 : single out link, over which all the writer tiles round-robin. */
535 27 : FOR(writer_tile_cnt) for( ulong j=0UL; j<exec_tile_cnt; j++ )
536 24 : fd_topob_tile_in( topo, "writer", i, "metric_in", "exec_writer", j, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
537 3 : /**/ fd_topob_tile_in ( topo, "tower", 0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
538 3 : /**/ fd_topob_tile_in ( topo, "tower", 0UL, "metric_in", "replay_tower", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
539 3 : if( snapshots_enabled ) {
540 0 : fd_topob_tile_in ( topo, "tower", 0UL, "metric_in", "snap_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
541 0 : }
542 3 : /**/ fd_topob_tile_out( topo, "tower", 0UL, "tower_out", 0UL );
543 3 : /**/ fd_topob_tile_in ( topo, "send", 0UL, "metric_in", "replay_stake", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
544 3 : /**/ fd_topob_tile_in ( topo, "send", 0UL, "metric_in", "gossip_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
545 3 : /**/ fd_topob_tile_in ( topo, "send", 0UL, "metric_in", "tower_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
546 3 : /**/ fd_topob_tile_out( topo, "send", 0UL, "send_net", 0UL );
547 3 : /**/ fd_topob_tile_out( topo, "send", 0UL, "send_txns", 0UL );
548 :
549 3 : FOR(quic_tile_cnt) fd_topob_tile_out( topo, "quic", i, "quic_verify", i );
550 3 : FOR(quic_tile_cnt) fd_topob_tile_out( topo, "quic", i, "quic_net", i );
551 : /* All verify tiles read from all QUIC tiles, packets are round robin. */
552 36 : FOR(verify_tile_cnt) for( ulong j=0UL; j<quic_tile_cnt; j++ )
553 18 : fd_topob_tile_in( topo, "verify", i, "metric_in", "quic_verify", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers, verify tiles may be overrun */
554 18 : FOR(verify_tile_cnt) fd_topob_tile_in( topo, "verify", i, "metric_in", "gossip_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
555 3 : /**/ fd_topob_tile_in( topo, "verify", 0UL, "metric_in", "send_txns", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
556 18 : FOR(verify_tile_cnt) fd_topob_tile_out( topo, "verify", i, "verify_dedup", i );
557 18 : FOR(verify_tile_cnt) fd_topob_tile_in( topo, "dedup", 0UL, "metric_in", "verify_dedup", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
558 3 : /**/ fd_topob_tile_in( topo, "dedup", 0UL, "metric_in", "executed_txn", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
559 3 : /**/ fd_topob_tile_out( topo, "dedup", 0UL, "dedup_resolv", 0UL );
560 3 : FOR(resolv_tile_cnt) fd_topob_tile_in( topo, "resolv", i, "metric_in", "dedup_resolv", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
561 3 : FOR(resolv_tile_cnt) fd_topob_tile_in( topo, "resolv", i, "metric_in", "replay_resol", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
562 3 : FOR(resolv_tile_cnt) fd_topob_tile_out( topo, "resolv", i, "resolv_pack", i );
563 3 : FOR(resolv_tile_cnt) fd_topob_tile_out( topo, "resolv", i, "resolv_repla", i );
564 3 : /**/ fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "resolv_pack", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
565 3 : /**/ fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "replay_pack", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
566 3 : /**/ fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "executed_txn", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
567 3 : fd_topob_tile_out( topo, "pack", 0UL, "pack_bank", 0UL );
568 3 : fd_topob_tile_out( topo, "pack", 0UL, "pack_poh" , 0UL );
569 3 : FOR(bank_tile_cnt) fd_topob_tile_in( topo, "pack", 0UL, "metric_in", "bank_pack", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
570 3 : FOR(bank_tile_cnt) fd_topob_tile_in( topo, "bank", i, "metric_in", "pack_bank", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
571 3 : FOR(bank_tile_cnt) fd_topob_tile_out( topo, "bank", i, "bank_poh", i );
572 3 : FOR(bank_tile_cnt) fd_topob_tile_out( topo, "bank", i, "bank_pack", i );
573 3 : FOR(bank_tile_cnt) fd_topob_tile_in( topo, "poh", 0UL, "metric_in", "bank_poh", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
574 3 : if( FD_LIKELY( config->tiles.pack.use_consumed_cus ) ) {
575 3 : /**/ fd_topob_tile_in( topo, "poh", 0UL, "metric_in", "pack_poh", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
576 3 : }
577 3 : /**/ fd_topob_tile_in( topo, "poh", 0UL, "metric_in", "replay_pack", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
578 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "poh_shred", 0UL );
579 3 : /**/ fd_topob_tile_out( topo, "poh", 0UL, "poh_replay", 0UL );
580 3 : FOR(shred_tile_cnt) fd_topob_tile_in ( topo, "shred", i, "metric_in", "replay_stake", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
581 3 : FOR(shred_tile_cnt) fd_topob_tile_in ( topo, "shred", i, "metric_in", "gossip_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
582 3 : FOR(shred_tile_cnt) fd_topob_tile_out( topo, "shred", i, "shred_repair", i );
583 3 : FOR(shred_tile_cnt) fd_topob_tile_in ( topo, "shred", i, "metric_in", "repair_shred", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
584 3 : FOR(shred_tile_cnt) fd_topob_tile_in ( topo, "shred", i, "metric_in", "ipecho_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
585 3 : FOR(shred_tile_cnt) fd_topob_tile_in ( topo, "shred", i, "metric_in", "poh_shred", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
586 3 : FOR(shred_tile_cnt) fd_topob_tile_out( topo, "shred", i, "shred_net", i );
587 :
588 : /* Sign links don't need to be reliable because they are synchronous,
589 : so there's at most one fragment in flight at a time anyway. The
590 : sign links are also not polled by fd_stem, instead the tiles will
591 : read the sign responses out of band in a dedicated spin loop.
592 :
593 : TODO: This can probably be fixed now to be relible ... ? */
594 : /* topo, tile_name, tile_kind_id, fseq_wksp, link_name, link_kind_id, reliable, polled */
595 3 : /**/ fd_topob_tile_in ( topo, "sign", 0UL, "metric_in", "gossip_sign", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
596 3 : /**/ fd_topob_tile_out( topo, "gossip", 0UL, "gossip_sign", 0UL );
597 3 : /**/ fd_topob_tile_in ( topo, "gossip", 0UL, "metric_in", "sign_gossip", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
598 3 : /**/ fd_topob_tile_out( topo, "sign", 0UL, "sign_gossip", 0UL );
599 :
600 6 : for( ulong i=0UL; i<shred_tile_cnt; i++ ) {
601 3 : /**/ fd_topob_tile_in ( topo, "sign", 0UL, "metric_in", "shred_sign", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
602 3 : /**/ fd_topob_tile_out( topo, "shred", i, "shred_sign", i );
603 3 : /**/ fd_topob_tile_in ( topo, "shred", i, "metric_in", "sign_shred", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
604 3 : /**/ fd_topob_tile_out( topo, "sign", 0UL, "sign_shred", i );
605 3 : }
606 :
607 3 : /**/ fd_topob_tile_in ( topo, "sign", 0UL, "metric_in", "ping_sign", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
608 3 : /**/ fd_topob_tile_out( topo, "repair", 0UL, "ping_sign", 0UL );
609 3 : /**/ fd_topob_tile_out( topo, "sign", 0UL, "sign_ping", 0UL );
610 :
611 3 : FOR(sign_tile_cnt-1UL) fd_topob_tile_out( topo, "repair", 0UL, "repair_sign", i );
612 3 : FOR(sign_tile_cnt-1UL) fd_topob_tile_in ( topo, "sign", i+1UL, "metric_in", "repair_sign", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
613 3 : FOR(sign_tile_cnt-1UL) fd_topob_tile_out( topo, "sign", i+1UL, "sign_repair", i );
614 3 : FOR(sign_tile_cnt-1UL) fd_topob_tile_in ( topo, "repair", 0UL, "metric_in", "sign_repair", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* This link is polled because the signing requests are asynchronous */
615 3 : /**/ fd_topob_tile_in ( topo, "repair", 0UL, "metric_in", "sign_ping", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
616 :
617 3 : /**/ fd_topob_tile_in ( topo, "sign", 0UL, "metric_in", "send_sign", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
618 3 : /**/ fd_topob_tile_out( topo, "send", 0UL, "send_sign", 0UL );
619 3 : /**/ fd_topob_tile_in ( topo, "send", 0UL, "metric_in", "sign_send", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
620 3 : /**/ fd_topob_tile_out( topo, "sign", 0UL, "sign_send", 0UL );
621 :
622 3 : if( FD_UNLIKELY( config->tiles.archiver.enabled ) ) {
623 0 : fd_topob_wksp( topo, "arch_f" );
624 0 : fd_topob_wksp( topo, "arch_w" );
625 0 : fd_topob_wksp( topo, "feeder" );
626 0 : fd_topob_wksp( topo, "arch_f2w" );
627 :
628 0 : fd_topob_link( topo, "feeder", "feeder", 65536UL, 4UL*FD_SHRED_STORE_MTU, 4UL+config->tiles.shred.max_pending_shred_sets );
629 0 : fd_topob_link( topo, "arch_f2w", "arch_f2w", 128UL, 4UL*FD_SHRED_STORE_MTU, 1UL );
630 :
631 0 : fd_topob_tile( topo, "arch_f", "arch_f", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
632 0 : fd_topob_tile( topo, "arch_w", "arch_w", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
633 :
634 0 : fd_topob_tile_out( topo, "replay", 0UL, "feeder", 0UL );
635 0 : fd_topob_tile_in( topo, "arch_f", 0UL, "metric_in", "feeder", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
636 :
637 0 : fd_topob_tile_out( topo, "arch_f", 0UL, "arch_f2w", 0UL );
638 0 : fd_topob_tile_in( topo, "arch_w", 0UL, "metric_in", "arch_f2w", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
639 0 : }
640 :
641 3 : if( FD_UNLIKELY( config->tiles.shredcap.enabled ) ) {
642 0 : fd_topob_wksp( topo, "scap" );
643 0 : fd_topob_wksp( topo, "repair_scap" );
644 0 : fd_topob_wksp( topo, "replay_scap" );
645 :
646 0 : fd_topob_tile( topo, "scap", "scap", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
647 :
648 0 : fd_topob_link( topo, "repair_scap", "repair_scap", 128UL, FD_SLICE_MAX_WITH_HEADERS, 1UL );
649 0 : fd_topob_link( topo, "replay_scap", "replay_scap", 128UL, sizeof(fd_hash_t)+sizeof(ulong), 1UL );
650 :
651 0 : fd_topob_tile_in( topo, "scap", 0UL, "metric_in", "repair_net", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
652 0 : for( ulong j=0UL; j<net_tile_cnt; j++ ) {
653 0 : fd_topob_tile_in( topo, "scap", 0UL, "metric_in", "net_shred", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
654 0 : }
655 0 : for( ulong j=0UL; j<shred_tile_cnt; j++ ) {
656 0 : fd_topob_tile_in( topo, "scap", 0UL, "metric_in", "shred_repair", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
657 0 : }
658 0 : fd_topob_tile_in( topo, "scap", 0UL, "metric_in", "gossip_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
659 :
660 0 : fd_topob_tile_in( topo, "scap", 0UL, "metric_in", "repair_scap", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
661 0 : fd_topob_tile_in( topo, "scap", 0UL, "metric_in", "replay_scap", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
662 :
663 0 : fd_topob_tile_out( topo, "repair", 0UL, "repair_scap", 0UL );
664 0 : fd_topob_tile_out( topo, "replay", 0UL, "replay_scap", 0UL );
665 :
666 : /* No default fd_topob_tile_in connection to stake_out */
667 0 : }
668 :
669 3 : fd_topob_wksp( topo, "replay_notif" );
670 : /* We may be notifying an external service, so always publish on this link. */
671 3 : fd_topob_link( topo, "replay_notif", "replay_notif", FD_REPLAY_NOTIF_DEPTH, FD_REPLAY_NOTIF_MTU, 1UL )->permit_no_consumers = 1;
672 3 : fd_topob_tile_out( topo, "replay", 0UL, "replay_notif", 0UL );
673 :
674 3 : int rpc_enabled = config->rpc.port;
675 3 : if( FD_UNLIKELY( rpc_enabled ) ) {
676 0 : fd_topob_wksp( topo, "rpcsrv" );
677 0 : fd_topob_tile( topo, "rpcsrv", "rpcsrv", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
678 0 : fd_topob_tile_in( topo, "rpcsrv", 0UL, "metric_in", "replay_notif", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
679 0 : fd_topob_tile_in( topo, "rpcsrv", 0UL, "metric_in", "replay_stake", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
680 0 : fd_topob_tile_in( topo, "rpcsrv", 0UL, "metric_in", "repair_repla", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
681 0 : fd_topob_tile_in( topo, "rpcsrv", 0UL, "metric_in", "replay_tower", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
682 0 : }
683 :
684 : /* For now the only plugin consumer is the GUI */
685 3 : int plugins_enabled = config->tiles.gui.enabled;
686 3 : if( FD_LIKELY( plugins_enabled ) ) {
687 3 : fd_topob_wksp( topo, "plugin_in" );
688 3 : fd_topob_wksp( topo, "plugin_out" );
689 3 : fd_topob_wksp( topo, "plugin" );
690 :
691 : /**/ fd_topob_link( topo, "plugin_out", "plugin_out", 128UL, 8UL+40200UL*(58UL+12UL*34UL), 1UL );
692 3 : /**/ fd_topob_link( topo, "replay_plugi", "plugin_in", 128UL, 4098*8UL, 1UL );
693 3 : /**/ fd_topob_link( topo, "votes_plugin", "plugin_in", 128UL, 8UL+40200UL*(58UL+12UL*34UL), 1UL );
694 :
695 : /**/ fd_topob_tile( topo, "plugin", "plugin", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
696 :
697 : /**/ fd_topob_tile_out( topo, "replay", 0UL, "replay_plugi", 0UL );
698 3 : /**/ fd_topob_tile_out( topo, "replay", 0UL, "votes_plugin", 0UL );
699 3 : /**/ fd_topob_tile_out( topo, "plugin", 0UL, "plugin_out", 0UL );
700 :
701 3 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "replay_plugi", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
702 3 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "replay_stake", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
703 3 : /**/ fd_topob_tile_in( topo, "plugin", 0UL, "metric_in", "votes_plugin", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
704 3 : }
705 :
706 3 : fd_topob_wksp( topo, "writ_repl" );
707 3 : FOR(writer_tile_cnt) fd_topob_link( topo, "writ_repl", "writ_repl", 16384UL, sizeof(fd_writer_replay_txn_finalized_msg_t), 1UL );
708 3 : FOR(writer_tile_cnt) fd_topob_tile_out( topo, "writer", i, "writ_repl", i );
709 3 : FOR(writer_tile_cnt) fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "writ_repl", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
710 3 : FOR(writer_tile_cnt) fd_topob_tile_in( topo, "writer", i, "metric_in", "send_txns", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
711 :
712 3 : if( FD_UNLIKELY( solcap_enabled ) ) {
713 : /* Capture account updates, whose updates must be centralized in the replay tile as solcap is currently not thread-safe.
714 : TODO: remove this when solcap v2 is here. */
715 0 : fd_topob_wksp( topo, "capt_replay" );
716 0 : FOR(writer_tile_cnt) fd_topob_link( topo, "capt_replay", "capt_replay", FD_CAPTURE_CTX_MAX_ACCOUNT_UPDATES, FD_CAPTURE_CTX_ACCOUNT_UPDATE_MSG_FOOTPRINT, 1UL );
717 0 : FOR(writer_tile_cnt) fd_topob_tile_out( topo, "writer", i, "capt_replay", i );
718 0 : FOR(writer_tile_cnt) fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "capt_replay", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
719 0 : }
720 :
721 3 : if( FD_LIKELY( config->tiles.gui.enabled ) ) {
722 3 : fd_topob_wksp( topo, "gui" );
723 3 : /**/ fd_topob_tile( topo, "gui", "gui", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
724 3 : /**/ fd_topob_tile_in( topo, "gui", 0UL, "metric_in", "plugin_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
725 3 : }
726 :
727 3 : if( FD_LIKELY( !is_auto_affinity ) ) {
728 0 : if( FD_UNLIKELY( affinity_tile_cnt<topo->tile_cnt ) )
729 0 : FD_LOG_ERR(( "The topology you are using has %lu tiles, but the CPU affinity specified in the config tile as [layout.affinity] only provides for %lu cores. "
730 0 : "You should either increase the number of cores dedicated to Firedancer in the affinity string, or decrease the number of cores needed by reducing "
731 0 : "the total tile count. You can reduce the tile count by decreasing individual tile counts in the [layout] section of the configuration file.",
732 0 : topo->tile_cnt, affinity_tile_cnt ));
733 0 : if( FD_UNLIKELY( affinity_tile_cnt>topo->tile_cnt ) )
734 0 : FD_LOG_WARNING(( "The topology you are using has %lu tiles, but the CPU affinity specified in the config tile as [layout.affinity] provides for %lu cores. "
735 0 : "Not all cores in the affinity will be used by Firedancer. You may wish to increase the number of tiles in the system by increasing "
736 0 : "individual tile counts in the [layout] section of the configuration file.",
737 0 : topo->tile_cnt, affinity_tile_cnt ));
738 0 : }
739 :
740 :
741 3 : if( FD_UNLIKELY( is_auto_affinity ) ) fd_topob_auto_layout( topo, 0 );
742 :
743 : /* There is a special fseq that sits between the pack, bank, and poh
744 : tiles to indicate when the bank/poh tiles are done processing a
745 : microblock. Pack uses this to determine when to "unlock" accounts
746 : that it marked as locked because they were being used. */
747 :
748 6 : for( ulong i=0UL; i<bank_tile_cnt; i++ ) {
749 3 : fd_topo_obj_t * busy_obj = fd_topob_obj( topo, "fseq", "bank_busy" );
750 :
751 3 : fd_topo_tile_t * poh_tile = &topo->tiles[ fd_topo_find_tile( topo, "poh", 0UL ) ];
752 3 : fd_topo_tile_t * pack_tile = &topo->tiles[ fd_topo_find_tile( topo, "pack", 0UL ) ];
753 3 : fd_topob_tile_uses( topo, poh_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
754 3 : fd_topob_tile_uses( topo, pack_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
755 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, busy_obj->id, "bank_busy.%lu", i ) );
756 3 : }
757 :
758 3 : fd_topo_obj_t * funk_obj = setup_topo_funk( topo, "funk",
759 3 : config->firedancer.funk.max_account_records,
760 3 : config->firedancer.funk.max_database_transactions,
761 3 : config->firedancer.funk.heap_size_gib,
762 3 : config->firedancer.funk.lock_pages );
763 3 : /**/ fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], funk_obj, FD_SHMEM_JOIN_MODE_READ_WRITE ); /* TODO: Should be readonly? */
764 24 : FOR(exec_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "exec", i ) ], funk_obj, FD_SHMEM_JOIN_MODE_READ_WRITE ); /* TODO: Should be readonly? */
765 3 : FOR(writer_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "writer", i ) ], funk_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
766 3 : FOR(bank_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "bank", i ) ], funk_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
767 3 : FOR(resolv_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "resolv", i ) ], funk_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
768 :
769 3 : fd_topo_obj_t * banks_obj = setup_topo_banks( topo, "banks", config->firedancer.runtime.max_total_banks, config->firedancer.runtime.max_fork_width );
770 3 : /**/ fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE ); /* TODO: Should be readonly? */
771 24 : FOR(exec_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "exec", i ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE ); /* TODO: Should be readonly? */
772 3 : FOR(writer_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "writer", i ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
773 3 : FOR(bank_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "bank", i ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
774 3 : FOR(resolv_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "resolv", i ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
775 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, banks_obj->id, "banks" ) );
776 :
777 : /* TODO: This should not exist in production */
778 3 : fd_topo_obj_t * bank_hash_cmp_obj = setup_topo_bank_hash_cmp( topo, "bh_cmp" );
779 3 : /**/ fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], bank_hash_cmp_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
780 24 : FOR(exec_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "exec", i ) ], bank_hash_cmp_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
781 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, bank_hash_cmp_obj->id, "bh_cmp" ) );
782 :
783 3 : ulong shred_depth = 65536UL; /* from fdctl/topology.c shred_store link. MAKE SURE TO KEEP IN SYNC. */
784 3 : ulong fec_set_cnt = shred_depth + config->tiles.shred.max_pending_shred_sets + 4UL;
785 3 : ulong fec_sets_sz = fec_set_cnt*sizeof(fd_shred34_t)*4; /* mirrors # of dcache entires in frankendancer */
786 3 : fd_topo_obj_t * fec_sets_obj = setup_topo_fec_sets( topo, "fec_sets", shred_tile_cnt*fec_sets_sz );
787 6 : for( ulong i=0UL; i<shred_tile_cnt; i++ ) {
788 3 : fd_topo_tile_t * shred_tile = &topo->tiles[ fd_topo_find_tile( topo, "shred", i ) ];
789 3 : fd_topob_tile_uses( topo, shred_tile, fec_sets_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
790 3 : }
791 3 : fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "repair", 0UL ) ], fec_sets_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
792 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, fec_sets_obj->id, "fec_sets" ) );
793 :
794 3 : fd_topo_obj_t * store_obj = setup_topo_store( topo, "store", config->firedancer.store.max_completed_shred_sets, (uint)shred_tile_cnt );
795 3 : FOR(shred_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "shred", i ) ], store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
796 3 : fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "repair", 0UL ) ], store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
797 3 : fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
798 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, store_obj->id, "store" ) );
799 :
800 3 : fd_topo_obj_t * txncache_obj = setup_topo_txncache( topo, "tcache",
801 3 : config->firedancer.runtime.max_rooted_slots,
802 3 : config->firedancer.runtime.max_live_slots,
803 3 : config->firedancer.runtime.max_transactions_per_slot );
804 3 : fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
805 3 : FD_TEST( fd_pod_insertf_ulong( topo->props, txncache_obj->id, "txncache" ) );
806 :
807 27 : for( ulong i=0UL; i<exec_tile_cnt; i++ ) {
808 24 : fd_topo_obj_t * exec_spad_obj = fd_topob_obj( topo, "exec_spad", "exec_spad" );
809 24 : fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], exec_spad_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
810 24 : fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "exec", i ) ], exec_spad_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
811 48 : for( ulong j=0UL; j<writer_tile_cnt; j++ ) {
812 : /* For txn_ctx. */
813 24 : fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "writer", j ) ], exec_spad_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
814 24 : }
815 24 : FD_TEST( fd_pod_insertf_ulong( topo->props, exec_spad_obj->id, "exec_spad.%lu", i ) );
816 24 : }
817 :
818 3 : fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "genesi", 0UL ) ], funk_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
819 3 : if( FD_LIKELY( snapshots_enabled ) ) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapin", 0UL ) ], funk_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
820 :
821 3 : if( FD_UNLIKELY( rpc_enabled ) ) {
822 0 : fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "rpcsrv", 0UL ) ], funk_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
823 0 : fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "rpcsrv", 0UL ) ], store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
824 0 : }
825 :
826 114 : for( ulong i=0UL; i<topo->tile_cnt; i++ ) fd_topo_configure_tile( &topo->tiles[ i ], config );
827 :
828 3 : FOR(net_tile_cnt) fd_topos_net_tile_finish( topo, i );
829 3 : fd_topob_finish( topo, CALLBACKS );
830 :
831 3 : const char * status_cache = config->tiles.replay.status_cache;
832 3 : if ( strlen( status_cache ) > 0 ) {
833 : /* Make the status cache workspace match the parameters used to create the
834 : checkpoint. This is a bit nonintuitive because of the way
835 : fd_topo_create_workspace works. */
836 0 : fd_wksp_preview_t preview[1];
837 0 : int err = fd_wksp_preview( status_cache, preview );
838 0 : if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "unable to preview %s: error %d", status_cache, err ));
839 0 : fd_topo_wksp_t * wksp = &topo->workspaces[ topo->objs[ txncache_obj->id ].wksp_id ];
840 0 : wksp->part_max = preview->part_max;
841 0 : wksp->known_footprint = 0;
842 0 : wksp->total_footprint = preview->data_max;
843 0 : ulong page_sz = FD_SHMEM_GIGANTIC_PAGE_SZ;
844 0 : wksp->page_sz = page_sz;
845 0 : ulong footprint = fd_wksp_footprint( preview->part_max, preview->data_max );
846 0 : wksp->page_cnt = footprint / page_sz;
847 0 : }
848 :
849 3 : config->topo = *topo;
850 3 : }
851 :
852 : void
853 : fd_topo_configure_tile( fd_topo_tile_t * tile,
854 111 : fd_config_t * config ) {
855 111 : int plugins_enabled = config->tiles.gui.enabled;
856 :
857 111 : if( FD_UNLIKELY( !strcmp( tile->name, "metric" ) ) ) {
858 :
859 3 : if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.metric.prometheus_listen_address, &tile->metric.prometheus_listen_addr ) ) )
860 0 : FD_LOG_ERR(( "failed to parse prometheus listen address `%s`", config->tiles.metric.prometheus_listen_address ));
861 3 : tile->metric.prometheus_listen_port = config->tiles.metric.prometheus_listen_port;
862 :
863 108 : } else if( FD_UNLIKELY( !strcmp( tile->name, "net" ) || !strcmp( tile->name, "sock" ) ) ) {
864 :
865 3 : tile->net.shred_listen_port = config->tiles.shred.shred_listen_port;
866 3 : tile->net.quic_transaction_listen_port = config->tiles.quic.quic_transaction_listen_port;
867 3 : tile->net.legacy_transaction_listen_port = config->tiles.quic.regular_transaction_listen_port;
868 3 : tile->net.gossip_listen_port = config->gossip.port;
869 3 : tile->net.repair_intake_listen_port = config->tiles.repair.repair_intake_listen_port;
870 3 : tile->net.repair_serve_listen_port = config->tiles.repair.repair_serve_listen_port;
871 3 : tile->net.send_src_port = config->tiles.send.send_src_port;
872 :
873 105 : } else if( FD_UNLIKELY( !strcmp( tile->name, "netlnk" ) ) ) {
874 :
875 102 : } else if( FD_UNLIKELY( !strcmp( tile->name, "ipecho") ) ) {
876 :
877 3 : tile->ipecho.expected_shred_version = config->consensus.expected_shred_version;
878 3 : tile->ipecho.bind_address = config->net.ip_addr;
879 3 : tile->ipecho.bind_port = config->gossip.port;
880 3 : tile->ipecho.entrypoints_cnt = config->gossip.entrypoints_cnt;
881 3 : fd_memcpy( tile->ipecho.entrypoints, config->gossip.resolved_entrypoints, tile->ipecho.entrypoints_cnt * sizeof(fd_ip4_port_t) );
882 :
883 99 : } else if( FD_UNLIKELY( !strcmp( tile->name, "genesi" ) ) ) {
884 :
885 3 : tile->genesi.funk_obj_id = fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX );
886 :
887 3 : tile->genesi.allow_download = config->firedancer.snapshots.genesis_download;
888 3 : strncpy( tile->genesi.genesis_path, config->paths.genesis, sizeof(tile->genesi.genesis_path) );
889 3 : tile->genesi.expected_shred_version = config->consensus.expected_shred_version;
890 3 : tile->genesi.entrypoints_cnt = config->gossip.entrypoints_cnt;
891 3 : fd_memcpy( tile->genesi.entrypoints, config->gossip.resolved_entrypoints, tile->genesi.entrypoints_cnt * sizeof(fd_ip4_port_t) );
892 :
893 96 : } else if( FD_UNLIKELY( !strcmp( tile->name, "gossvf") ) ) {
894 :
895 3 : strncpy( tile->gossvf.identity_key_path, config->paths.identity_key, sizeof(tile->gossvf.identity_key_path) );
896 3 : tile->gossvf.tcache_depth = 1<<22UL; /* TODO: user defined option */
897 3 : tile->gossvf.shred_version = 0U;
898 3 : tile->gossvf.allow_private_address = config->development.gossip.allow_private_address;
899 3 : tile->gossvf.boot_timestamp_nanos = config->boot_timestamp_nanos;
900 :
901 3 : tile->gossvf.entrypoints_cnt = config->gossip.entrypoints_cnt;
902 3 : fd_memcpy( tile->gossvf.entrypoints, config->gossip.resolved_entrypoints, tile->gossvf.entrypoints_cnt * sizeof(fd_ip4_port_t) );
903 :
904 93 : } else if( FD_UNLIKELY( !strcmp( tile->name, "gossip" ) ) ) {
905 :
906 3 : if( FD_UNLIKELY( strcmp( config->firedancer.gossip.host, "" ) ) ) {
907 0 : if( !resolve_address( config->firedancer.gossip.host, &tile->gossip.ip_addr ) )
908 0 : FD_LOG_ERR(( "could not resolve [gossip.host] %s", config->firedancer.gossip.host ));
909 3 : } else {
910 3 : tile->gossip.ip_addr = config->net.ip_addr;
911 3 : }
912 3 : strncpy( tile->gossip.identity_key_path, config->paths.identity_key, sizeof(tile->gossip.identity_key_path) );
913 3 : tile->gossip.shred_version = config->consensus.expected_shred_version;
914 3 : tile->gossip.max_entries = config->tiles.gossip.max_entries;
915 3 : tile->gossip.boot_timestamp_nanos = config->boot_timestamp_nanos;
916 :
917 3 : tile->gossip.ip_addr = config->net.ip_addr;
918 :
919 3 : tile->gossip.ports.gossip = config->gossip.port;
920 3 : tile->gossip.ports.tvu = config->tiles.shred.shred_listen_port;
921 3 : tile->gossip.ports.tpu = config->tiles.quic.regular_transaction_listen_port;
922 3 : tile->gossip.ports.tpu_quic = config->tiles.quic.quic_transaction_listen_port;
923 3 : tile->gossip.ports.repair = config->tiles.repair.repair_intake_listen_port;
924 :
925 3 : tile->gossip.entrypoints_cnt = config->gossip.entrypoints_cnt;
926 3 : fd_memcpy( tile->gossip.entrypoints, config->gossip.resolved_entrypoints, tile->gossip.entrypoints_cnt * sizeof(fd_ip4_port_t) );
927 :
928 90 : } else if( FD_UNLIKELY( !strcmp( tile->name, "snaprd" ) ) ) {
929 :
930 0 : fd_memcpy( tile->snaprd.snapshots_path, config->paths.snapshots, PATH_MAX );
931 0 : tile->snaprd.diagnostics = 1;
932 0 : tile->snaprd.incremental_snapshot_fetch = config->firedancer.snapshots.incremental_snapshots;
933 0 : tile->snaprd.do_download = config->firedancer.snapshots.download;
934 0 : tile->snaprd.maximum_local_snapshot_age = config->firedancer.snapshots.maximum_local_snapshot_age;
935 0 : tile->snaprd.minimum_download_speed_mib = config->firedancer.snapshots.minimum_download_speed_mib;
936 0 : tile->snaprd.maximum_download_retry_abort = config->firedancer.snapshots.maximum_download_retry_abort;
937 0 : tile->snaprd.max_full_snapshots_to_keep = config->firedancer.snapshots.max_full_snapshots_to_keep;
938 0 : tile->snaprd.max_incremental_snapshots_to_keep = config->firedancer.snapshots.max_incremental_snapshots_to_keep;
939 :
940 0 : ulong peers_cnt = config->firedancer.snapshots.sources.http.peers_cnt;
941 0 : ulong resolved_peers_cnt = 0UL;
942 :
943 0 : for( ulong j=0UL; j<peers_cnt; j++ ) {
944 0 : if( FD_UNLIKELY( !config->firedancer.snapshots.sources.http.peers[ j ].enabled ) ) continue;
945 :
946 0 : if( FD_UNLIKELY( 0==resolve_peer( config->firedancer.snapshots.sources.http.peers[ j ].url, &tile->snaprd.http.peers[ resolved_peers_cnt ] ) ) ) {
947 0 : FD_LOG_ERR(( "failed to resolve address of [snapshots.sources.http.peers] entry \"%s\"", config->firedancer.snapshots.sources.http.peers[ j ].url ));
948 0 : } else {
949 0 : resolved_peers_cnt++;
950 0 : }
951 0 : }
952 :
953 0 : tile->snaprd.http.peers_cnt = resolved_peers_cnt;
954 : /* TODO: set up known validators and known validators cnt */
955 :
956 90 : } else if( FD_UNLIKELY( !strcmp( tile->name, "snapdc" ) ) ) {
957 :
958 90 : } else if( FD_UNLIKELY( !strcmp( tile->name, "snapin" ) ) ) {
959 :
960 0 : tile->snapin.funk_obj_id = fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX );
961 :
962 90 : } else if( FD_UNLIKELY( !strcmp( tile->name, "repair" ) ) ) {
963 3 : tile->repair.max_pending_shred_sets = config->tiles.shred.max_pending_shred_sets;
964 3 : tile->repair.repair_intake_listen_port = config->tiles.repair.repair_intake_listen_port;
965 3 : tile->repair.repair_serve_listen_port = config->tiles.repair.repair_serve_listen_port;
966 3 : tile->repair.slot_max = config->tiles.repair.slot_max;
967 :
968 3 : strncpy( tile->repair.identity_key_path, config->paths.identity_key, sizeof(tile->repair.identity_key_path) );
969 :
970 87 : } else if( FD_UNLIKELY( !strcmp( tile->name, "replay" ) )) {
971 :
972 3 : tile->replay.fec_max = config->tiles.shred.max_pending_shred_sets;
973 3 : tile->replay.max_vote_accounts = config->firedancer.runtime.max_vote_accounts;
974 :
975 : /* specified by [tiles.replay] */
976 :
977 3 : strncpy( tile->replay.blockstore_file, config->firedancer.blockstore.file, sizeof(tile->replay.blockstore_file) );
978 3 : strncpy( tile->replay.blockstore_checkpt, config->firedancer.blockstore.checkpt, sizeof(tile->replay.blockstore_checkpt) );
979 :
980 3 : tile->replay.tx_metadata_storage = config->rpc.extended_tx_metadata_storage;
981 :
982 3 : tile->replay.funk_obj_id = fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX );
983 :
984 3 : tile->replay.bootstrap = !config->gossip.entrypoints_cnt;
985 3 : strncpy( tile->replay.genesis_path, config->paths.genesis, sizeof(tile->replay.genesis_path) );
986 :
987 3 : strncpy( tile->replay.cluster_version, config->tiles.replay.cluster_version, sizeof(tile->replay.cluster_version) );
988 3 : strncpy( tile->replay.tower_checkpt, config->tiles.replay.tower_checkpt, sizeof(tile->replay.tower_checkpt) );
989 :
990 3 : tile->replay.heap_size_gib = config->tiles.replay.heap_size_gib;
991 :
992 : /* not specified by [tiles.replay] */
993 :
994 3 : strncpy( tile->replay.identity_key_path, config->paths.identity_key, sizeof(tile->replay.identity_key_path) );
995 3 : tile->replay.ip_addr = config->net.ip_addr;
996 3 : strncpy( tile->replay.vote_account_path, config->paths.vote_account, sizeof(tile->replay.vote_account_path) );
997 3 : tile->replay.enable_bank_hash_cmp = 1;
998 :
999 3 : tile->replay.capture_start_slot = config->capture.capture_start_slot;
1000 3 : strncpy( tile->replay.solcap_capture, config->capture.solcap_capture, sizeof(tile->replay.solcap_capture) );
1001 3 : strncpy( tile->replay.dump_proto_dir, config->capture.dump_proto_dir, sizeof(tile->replay.dump_proto_dir) );
1002 3 : tile->replay.dump_block_to_pb = config->capture.dump_block_to_pb;
1003 :
1004 3 : FD_TEST( tile->replay.funk_obj_id == fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX ) );
1005 :
1006 84 : } else if( FD_UNLIKELY( !strcmp( tile->name, "exec" ) ) ) {
1007 :
1008 24 : tile->exec.funk_obj_id = fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX );
1009 :
1010 24 : tile->exec.capture_start_slot = config->capture.capture_start_slot;
1011 24 : strncpy( tile->exec.dump_proto_dir, config->capture.dump_proto_dir, sizeof(tile->exec.dump_proto_dir) );
1012 24 : tile->exec.dump_instr_to_pb = config->capture.dump_instr_to_pb;
1013 24 : tile->exec.dump_txn_to_pb = config->capture.dump_txn_to_pb;
1014 24 : tile->exec.dump_syscall_to_pb = config->capture.dump_syscall_to_pb;
1015 24 : tile->exec.dump_elf_to_pb = config->capture.dump_elf_to_pb;
1016 :
1017 60 : } else if( FD_UNLIKELY( !strcmp( tile->name, "writer" ) ) ) {
1018 :
1019 3 : tile->writer.funk_obj_id = fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX );
1020 3 : strncpy( tile->writer.solcap_capture, config->capture.solcap_capture, sizeof(tile->writer.solcap_capture) );
1021 3 : tile->writer.capture_start_slot = config->capture.capture_start_slot;
1022 :
1023 57 : } else if( FD_UNLIKELY( !strcmp( tile->name, "tower" ) ) ) {
1024 :
1025 3 : strncpy( tile->tower.identity_key_path, config->paths.identity_key, sizeof(tile->tower.identity_key_path) );
1026 3 : strncpy( tile->tower.vote_acc_path, config->paths.vote_account, sizeof(tile->tower.vote_acc_path) );
1027 3 : strncpy( tile->tower.ledger_path, config->paths.ledger, sizeof(tile->tower.ledger_path) );
1028 :
1029 54 : } else if( FD_UNLIKELY( !strcmp( tile->name, "send" ) ) ) {
1030 :
1031 3 : tile->send.send_src_port = config->tiles.send.send_src_port;
1032 3 : tile->send.ip_addr = config->net.ip_addr;
1033 3 : strncpy( tile->send.identity_key_path, config->paths.identity_key, sizeof(tile->send.identity_key_path) );
1034 :
1035 51 : } else if( FD_UNLIKELY( !strcmp( tile->name, "quic" ) ) ) {
1036 :
1037 3 : tile->quic.reasm_cnt = config->tiles.quic.txn_reassembly_count;
1038 3 : tile->quic.out_depth = config->tiles.verify.receive_buffer_size;
1039 3 : tile->quic.max_concurrent_connections = config->tiles.quic.max_concurrent_connections;
1040 3 : tile->quic.max_concurrent_handshakes = config->tiles.quic.max_concurrent_handshakes;
1041 3 : tile->quic.quic_transaction_listen_port = config->tiles.quic.quic_transaction_listen_port;
1042 3 : tile->quic.idle_timeout_millis = config->tiles.quic.idle_timeout_millis;
1043 3 : tile->quic.ack_delay_millis = config->tiles.quic.ack_delay_millis;
1044 3 : tile->quic.retry = config->tiles.quic.retry;
1045 3 : fd_cstr_fini( fd_cstr_append_cstr_safe( fd_cstr_init( tile->quic.key_log_path ), config->tiles.quic.ssl_key_log_file, sizeof(tile->quic.key_log_path) ) );
1046 :
1047 48 : } else if( FD_UNLIKELY( !strcmp( tile->name, "verify" ) ) ) {
1048 :
1049 18 : tile->verify.tcache_depth = config->tiles.verify.signature_cache_size;
1050 :
1051 30 : } else if( FD_UNLIKELY( !strcmp( tile->name, "dedup" ) ) ) {
1052 :
1053 3 : tile->dedup.tcache_depth = config->tiles.dedup.signature_cache_size;
1054 :
1055 27 : } else if( FD_UNLIKELY( !strcmp( tile->name, "resolv" ) ) ) {
1056 :
1057 3 : tile->resolv.funk_obj_id = fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX );
1058 :
1059 24 : } else if( FD_UNLIKELY( !strcmp( tile->name, "pack" ) ) ) {
1060 :
1061 3 : tile->pack.max_pending_transactions = config->tiles.pack.max_pending_transactions;
1062 3 : tile->pack.bank_tile_count = config->layout.bank_tile_count;
1063 3 : tile->pack.larger_max_cost_per_block = config->development.bench.larger_max_cost_per_block;
1064 3 : tile->pack.larger_shred_limits_per_block = config->development.bench.larger_shred_limits_per_block;
1065 3 : tile->pack.use_consumed_cus = config->tiles.pack.use_consumed_cus;
1066 3 : tile->pack.schedule_strategy = config->tiles.pack.schedule_strategy_enum;
1067 :
1068 3 : if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
1069 0 : #define PARSE_PUBKEY( _tile, f ) \
1070 0 : if( FD_UNLIKELY( !fd_base58_decode_32( config->tiles.bundle.f, tile->_tile.bundle.f ) ) ) \
1071 0 : FD_LOG_ERR(( "[tiles.bundle.enabled] set to true, but failed to parse [tiles.bundle."#f"] %s", config->tiles.bundle.f ));
1072 0 : tile->pack.bundle.enabled = 1;
1073 0 : PARSE_PUBKEY( pack, tip_distribution_program_addr );
1074 0 : PARSE_PUBKEY( pack, tip_payment_program_addr );
1075 0 : PARSE_PUBKEY( pack, tip_distribution_authority );
1076 0 : tile->pack.bundle.commission_bps = config->tiles.bundle.commission_bps;
1077 0 : strncpy( tile->pack.bundle.identity_key_path, config->paths.identity_key, sizeof(tile->pack.bundle.identity_key_path) );
1078 0 : strncpy( tile->pack.bundle.vote_account_path, config->paths.vote_account, sizeof(tile->pack.bundle.vote_account_path) );
1079 3 : } else {
1080 3 : fd_memset( &tile->pack.bundle, '\0', sizeof(tile->pack.bundle) );
1081 3 : }
1082 :
1083 21 : } else if( FD_UNLIKELY( !strcmp( tile->name, "bank" ) ) ) {
1084 3 : tile->bank.funk_obj_id = fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX );
1085 :
1086 18 : } else if( FD_UNLIKELY( !strcmp( tile->name, "poh" ) ) ) {
1087 3 : strncpy( tile->poh.identity_key_path, config->paths.identity_key, sizeof(tile->poh.identity_key_path) );
1088 :
1089 3 : tile->poh.plugins_enabled = plugins_enabled;
1090 3 : tile->poh.bank_cnt = config->layout.bank_tile_count;
1091 3 : tile->poh.lagged_consecutive_leader_start = config->tiles.poh.lagged_consecutive_leader_start;
1092 :
1093 3 : if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
1094 0 : tile->poh.bundle.enabled = 1;
1095 0 : PARSE_PUBKEY( poh, tip_distribution_program_addr );
1096 0 : PARSE_PUBKEY( poh, tip_payment_program_addr );
1097 0 : strncpy( tile->poh.bundle.vote_account_path, config->paths.vote_account, sizeof(tile->poh.bundle.vote_account_path) );
1098 0 : #undef PARSE_PUBKEY
1099 3 : } else {
1100 3 : fd_memset( &tile->poh.bundle, '\0', sizeof(tile->poh.bundle) );
1101 3 : }
1102 :
1103 15 : } else if( FD_UNLIKELY( !strcmp( tile->name, "shred" ) ) ) {
1104 :
1105 3 : strncpy( tile->shred.identity_key_path, config->paths.identity_key, sizeof(tile->shred.identity_key_path) );
1106 :
1107 3 : tile->shred.depth = config->topo.links[ tile->out_link_id[ 0 ] ].depth;
1108 3 : tile->shred.fec_resolver_depth = config->tiles.shred.max_pending_shred_sets;
1109 3 : tile->shred.expected_shred_version = config->consensus.expected_shred_version;
1110 3 : tile->shred.shred_listen_port = config->tiles.shred.shred_listen_port;
1111 3 : tile->shred.larger_shred_limits_per_block = config->development.bench.larger_shred_limits_per_block;
1112 3 : for( ulong i=0UL; i<config->tiles.shred.additional_shred_destinations_retransmit_cnt; i++ ) {
1113 0 : parse_ip_port( "tiles.shred.additional_shred_destinations_retransmit",
1114 0 : config->tiles.shred.additional_shred_destinations_retransmit[ i ],
1115 0 : &tile->shred.adtl_dests_retransmit[ i ] );
1116 0 : }
1117 3 : tile->shred.adtl_dests_retransmit_cnt = config->tiles.shred.additional_shred_destinations_retransmit_cnt;
1118 3 : for( ulong i=0UL; i<config->tiles.shred.additional_shred_destinations_leader_cnt; i++ ) {
1119 0 : parse_ip_port( "tiles.shred.additional_shred_destinations_leader",
1120 0 : config->tiles.shred.additional_shred_destinations_leader[ i ],
1121 0 : &tile->shred.adtl_dests_leader[ i ] );
1122 0 : }
1123 3 : tile->shred.adtl_dests_leader_cnt = config->tiles.shred.additional_shred_destinations_leader_cnt;
1124 :
1125 12 : } else if( FD_UNLIKELY( !strcmp( tile->name, "sign" ) ) ) {
1126 :
1127 6 : strncpy( tile->sign.identity_key_path, config->paths.identity_key, sizeof(tile->sign.identity_key_path) );
1128 :
1129 6 : } else if( FD_UNLIKELY( !strcmp( tile->name, "plugin" ) ) ) {
1130 :
1131 3 : } else if( FD_UNLIKELY( !strcmp( tile->name, "gui" ) ) ) {
1132 :
1133 3 : if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.gui.gui_listen_address, &tile->gui.listen_addr ) ) )
1134 0 : FD_LOG_ERR(( "failed to parse gui listen address `%s`", config->tiles.gui.gui_listen_address ));
1135 3 : tile->gui.listen_port = config->tiles.gui.gui_listen_port;
1136 3 : tile->gui.is_voting = strcmp( config->paths.vote_account, "" );
1137 3 : strncpy( tile->gui.cluster, config->cluster, sizeof(tile->gui.cluster) );
1138 3 : strncpy( tile->gui.identity_key_path, config->paths.identity_key, sizeof(tile->gui.identity_key_path) );
1139 3 : strncpy( tile->gui.vote_key_path, config->paths.vote_account, sizeof(tile->gui.vote_key_path) );
1140 3 : tile->gui.max_http_connections = config->tiles.gui.max_http_connections;
1141 3 : tile->gui.max_websocket_connections = config->tiles.gui.max_websocket_connections;
1142 3 : tile->gui.max_http_request_length = config->tiles.gui.max_http_request_length;
1143 3 : tile->gui.send_buffer_size_mb = config->tiles.gui.send_buffer_size_mb;
1144 3 : tile->gui.schedule_strategy = config->tiles.pack.schedule_strategy_enum;
1145 :
1146 3 : } else if( FD_UNLIKELY( !strcmp( tile->name, "rpcsrv" ) ) ) {
1147 :
1148 0 : strncpy( tile->replay.blockstore_file, config->firedancer.blockstore.file, sizeof(tile->replay.blockstore_file) );
1149 0 : tile->rpcserv.funk_obj_id = fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX );
1150 0 : tile->rpcserv.store_obj_id = fd_pod_query_ulong( config->topo.props, "store", ULONG_MAX );
1151 0 : tile->rpcserv.rpc_port = config->rpc.port;
1152 0 : tile->rpcserv.tpu_port = config->tiles.quic.regular_transaction_listen_port;
1153 0 : tile->rpcserv.tpu_ip_addr = config->net.ip_addr;
1154 0 : tile->rpcserv.block_index_max = config->rpc.block_index_max;
1155 0 : tile->rpcserv.txn_index_max = config->rpc.txn_index_max;
1156 0 : tile->rpcserv.acct_index_max = config->rpc.acct_index_max;
1157 0 : strncpy( tile->rpcserv.history_file, config->rpc.history_file, sizeof(tile->rpcserv.history_file) );
1158 0 : strncpy( tile->rpcserv.identity_key_path, config->paths.identity_key, sizeof(tile->rpcserv.identity_key_path) );
1159 :
1160 0 : } else if( FD_UNLIKELY( !strcmp( tile->name, "arch_f" ) ||
1161 0 : !strcmp( tile->name, "arch_w" ) ) ) {
1162 :
1163 0 : strncpy( tile->archiver.rocksdb_path, config->tiles.archiver.rocksdb_path, sizeof(tile->archiver.rocksdb_path) );
1164 :
1165 0 : } else if( FD_UNLIKELY( !strcmp( tile->name, "back" ) ) ) {
1166 :
1167 0 : tile->archiver.end_slot = config->tiles.archiver.end_slot;
1168 0 : strncpy( tile->archiver.ingest_mode, config->tiles.archiver.ingest_mode, sizeof(tile->archiver.ingest_mode) );
1169 0 : if( FD_UNLIKELY( 0==strlen( tile->archiver.ingest_mode ) ) ) {
1170 0 : FD_LOG_ERR(( "`archiver.ingest_mode` not specified in toml" ));
1171 0 : }
1172 :
1173 : /* Validate arguments based on the ingest mode */
1174 0 : if( !strcmp( tile->archiver.ingest_mode, "rocksdb" ) ) {
1175 0 : strncpy( tile->archiver.rocksdb_path, config->tiles.archiver.rocksdb_path, PATH_MAX );
1176 0 : if( FD_UNLIKELY( 0==strlen( tile->archiver.rocksdb_path ) ) ) {
1177 0 : FD_LOG_ERR(( "`archiver.rocksdb_path` not specified in toml" ));
1178 0 : }
1179 0 : } else if( !strcmp( tile->archiver.ingest_mode, "shredcap" ) ) {
1180 0 : strncpy( tile->archiver.shredcap_path, config->tiles.archiver.shredcap_path, PATH_MAX );
1181 0 : if( FD_UNLIKELY( 0==strlen( tile->archiver.shredcap_path ) ) ) {
1182 0 : FD_LOG_ERR(( "`archiver.shredcap_path` not specified in toml" ));
1183 0 : }
1184 0 : strncpy( tile->archiver.bank_hash_path, config->tiles.archiver.bank_hash_path, PATH_MAX );
1185 0 : if( FD_UNLIKELY( 0==strlen( tile->archiver.bank_hash_path ) ) ) {
1186 0 : FD_LOG_ERR(( "`archiver.bank_hash_path` not specified in toml" ));
1187 0 : }
1188 0 : } else {
1189 0 : FD_LOG_ERR(( "Invalid ingest mode: %s", tile->archiver.ingest_mode ));
1190 0 : }
1191 :
1192 0 : } else if( FD_UNLIKELY( !strcmp( tile->name, "scap" ) ) ) {
1193 :
1194 0 : tile->shredcap.repair_intake_listen_port = config->tiles.repair.repair_intake_listen_port;
1195 0 : strncpy( tile->shredcap.folder_path, config->tiles.shredcap.folder_path, sizeof(tile->shredcap.folder_path) );
1196 0 : tile->shredcap.write_buffer_size = config->tiles.shredcap.write_buffer_size;
1197 0 : tile->shredcap.enable_publish_stake_weights = 0; /* this is not part of the config */
1198 0 : strncpy( tile->shredcap.manifest_path, "", PATH_MAX ); /* this is not part of the config */
1199 :
1200 0 : } else {
1201 0 : FD_LOG_ERR(( "unknown tile name `%s`", tile->name ));
1202 0 : }
1203 111 : }
|