LCOV - code coverage report
Current view: top level - app/firedancer - topology.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 607 878 69.1 %
Date: 2025-09-18 04:41:32 Functions: 9 22 40.9 %

          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 : }

Generated by: LCOV version 1.14