LCOV - code coverage report
Current view: top level - app/firedancer - topology.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 1107 0.0 %
Date: 2025-12-06 04:45:29 Functions: 0 27 0.0 %

          Line data    Source code
       1             : #include "topology.h"
       2             : 
       3             : #include "../../ballet/lthash/fd_lthash.h"
       4             : #include "../../choreo/fd_choreo_base.h"
       5             : #include "../../discof/reasm/fd_reasm.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 "../../discof/repair/fd_repair.h"
      12             : #include "../../discof/replay/fd_replay_tile.h"
      13             : #include "../../disco/net/fd_net_tile.h"
      14             : #include "../../discof/restore/fd_snapct_tile.h"
      15             : #include "../../disco/gui/fd_gui_peers.h"
      16             : #include "../../disco/quic/fd_tpu.h"
      17             : #include "../../disco/pack/fd_pack_cost.h"
      18             : #include "../../disco/tiles.h"
      19             : #include "../../disco/topo/fd_topob.h"
      20             : #include "../../disco/topo/fd_cpu_topo.h"
      21             : #include "../../util/pod/fd_pod_format.h"
      22             : #include "../../util/tile/fd_tile_private.h"
      23             : #include "../../discof/restore/utils/fd_ssctrl.h"
      24             : #include "../../discof/restore/utils/fd_ssmsg.h"
      25             : #include "../../flamenco/progcache/fd_progcache_admin.h"
      26             : #include "../../vinyl/meta/fd_vinyl_meta.h"
      27             : #include "../../vinyl/io/fd_vinyl_io.h" /* FD_VINYL_IO_TYPE_* */
      28             : 
      29             : #include <sys/random.h>
      30             : #include <sys/types.h>
      31             : #include <sys/socket.h>
      32             : #include <stdlib.h>
      33             : #include <netdb.h>
      34             : 
      35             : extern fd_topo_obj_callbacks_t * CALLBACKS[];
      36             : 
      37             : static void
      38           0 : parse_ip_port( const char * name, const char * ip_port, fd_topo_ip_port_t *parsed_ip_port) {
      39           0 :   char buf[ sizeof( "255.255.255.255:65536" ) ];
      40           0 :   memcpy( buf, ip_port, sizeof( buf ) );
      41           0 :   char *ip_end = strchr( buf, ':' );
      42           0 :   if( FD_UNLIKELY( !ip_end ) )
      43           0 :     FD_LOG_ERR(( "[%s] must in the form ip:port", name ));
      44           0 :   *ip_end = '\0';
      45             : 
      46           0 :   if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( buf, &( parsed_ip_port->ip ) ) ) ) {
      47           0 :     FD_LOG_ERR(( "could not parse IP %s in [%s]", buf, name ));
      48           0 :   }
      49             : 
      50           0 :   parsed_ip_port->port = fd_cstr_to_ushort( ip_end+1 );
      51           0 :   if( FD_UNLIKELY( !parsed_ip_port->port ) )
      52           0 :     FD_LOG_ERR(( "could not parse port %s in [%s]", ip_end+1, name ));
      53           0 : }
      54             : 
      55             : fd_topo_obj_t *
      56             : setup_topo_banks( fd_topo_t *  topo,
      57             :                   char const * wksp_name,
      58             :                   ulong        max_live_slots,
      59             :                   ulong        max_fork_width,
      60           0 :                   int          larger_max_cost_per_block ) {
      61           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "banks", wksp_name );
      62           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_live_slots, "obj.%lu.max_live_slots", obj->id ) );
      63           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_fork_width, "obj.%lu.max_fork_width", obj->id ) );
      64           0 :   FD_TEST( fd_pod_insertf_int( topo->props, larger_max_cost_per_block, "obj.%lu.larger_max_cost_per_block", obj->id ) );
      65           0 :   ulong seed;
      66           0 :   FD_TEST( fd_rng_secure( &seed, sizeof( ulong ) ) );
      67           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, seed, "obj.%lu.seed", obj->id ) );
      68           0 :   return obj;
      69           0 : }
      70             : 
      71             : static fd_topo_obj_t *
      72           0 : setup_topo_fec_sets( fd_topo_t * topo, char const * wksp_name, ulong sz ) {
      73           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "fec_sets", wksp_name );
      74           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, sz, "obj.%lu.sz",   obj->id ) );
      75           0 :   return obj;
      76           0 : }
      77             : 
      78             : fd_topo_obj_t *
      79             : setup_topo_funk( fd_topo_t *  topo,
      80             :                  char const * wksp_name,
      81             :                  ulong        max_account_records,
      82             :                  ulong        max_database_transactions,
      83           0 :                  ulong        heap_size_gib ) {
      84           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "funk", wksp_name );
      85           0 :   FD_TEST( fd_pod_insert_ulong(  topo->props, "funk", obj->id ) );
      86           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_account_records,       "obj.%lu.rec_max",  obj->id ) );
      87           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_database_transactions, "obj.%lu.txn_max",  obj->id ) );
      88           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, heap_size_gib*(1UL<<30),   "obj.%lu.heap_max", obj->id ) );
      89           0 :   ulong funk_footprint = fd_funk_footprint( max_database_transactions, max_account_records );
      90           0 :   if( FD_UNLIKELY( !funk_footprint ) ) FD_LOG_ERR(( "Invalid [funk] parameters" ));
      91             : 
      92             :   /* Increase workspace partition count */
      93           0 :   ulong wksp_idx = fd_topo_find_wksp( topo, wksp_name );
      94           0 :   FD_TEST( wksp_idx!=ULONG_MAX );
      95           0 :   fd_topo_wksp_t * wksp = &topo->workspaces[ wksp_idx ];
      96           0 :   ulong size     = funk_footprint+(heap_size_gib*(1UL<<30));
      97           0 :   ulong part_max = fd_wksp_part_max_est( size, 1U<<14U );
      98           0 :   if( FD_UNLIKELY( !part_max ) ) FD_LOG_ERR(( "fd_wksp_part_max_est(%lu,16KiB) failed", size ));
      99           0 :   wksp->part_max += part_max;
     100             : 
     101           0 :   return obj;
     102           0 : }
     103             : 
     104             : fd_topo_obj_t *
     105             : setup_topo_progcache( fd_topo_t *  topo,
     106             :                       char const * wksp_name,
     107             :                       ulong        max_cache_entries,
     108             :                       ulong        max_database_transactions,
     109           0 :                       ulong        heap_size ) {
     110           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "funk", wksp_name );
     111           0 :   FD_TEST( fd_pod_insert_ulong(  topo->props, "progcache", obj->id ) );
     112           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_cache_entries,         "obj.%lu.rec_max",  obj->id ) );
     113           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_database_transactions, "obj.%lu.txn_max",  obj->id ) );
     114           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, heap_size,                 "obj.%lu.heap_max", obj->id ) );
     115           0 :   ulong funk_footprint = fd_funk_footprint( max_database_transactions, max_cache_entries );
     116           0 :   if( FD_UNLIKELY( !funk_footprint ) ) FD_LOG_ERR(( "Invalid [runtime.program_cache] parameters" ));
     117           0 :   if( FD_UNLIKELY( heap_size<(2*funk_footprint) ) ) {
     118           0 :     FD_LOG_ERR(( "Invalid [runtime.program_cache] parameters: heap_size_mib should be at least %lu",
     119           0 :                  ( 2*funk_footprint )>>20 ));
     120           0 :   }
     121             : 
     122             :   /* Increase workspace partition count */
     123           0 :   ulong wksp_idx = fd_topo_find_wksp( topo, wksp_name );
     124           0 :   FD_TEST( wksp_idx!=ULONG_MAX );
     125           0 :   fd_topo_wksp_t * wksp = &topo->workspaces[ wksp_idx ];
     126           0 :   ulong part_max = fd_wksp_part_max_est( heap_size, 1U<<14U );
     127           0 :   if( FD_UNLIKELY( !part_max ) ) FD_LOG_ERR(( "fd_wksp_part_max_est(%lu,16KiB) failed", funk_footprint ));
     128           0 :   wksp->part_max += part_max;
     129             : 
     130           0 :   return obj;
     131           0 : }
     132             : 
     133             : fd_topo_obj_t *
     134             : setup_topo_store( fd_topo_t *  topo,
     135             :                   char const * wksp_name,
     136             :                   ulong        fec_max,
     137           0 :                   uint         part_cnt ) {
     138           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "store", wksp_name );
     139           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, fec_max,  "obj.%lu.fec_max",  obj->id ) );
     140           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, part_cnt, "obj.%lu.part_cnt", obj->id ) );
     141           0 :   return obj;
     142           0 : }
     143             : 
     144             : fd_topo_obj_t *
     145             : setup_topo_txncache( fd_topo_t *  topo,
     146             :                      char const * wksp_name,
     147             :                      ulong        max_live_slots,
     148           0 :                      ulong        max_txn_per_slot ) {
     149           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "txncache", wksp_name );
     150             : 
     151           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_live_slots,   "obj.%lu.max_live_slots",   obj->id ) );
     152           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_txn_per_slot, "obj.%lu.max_txn_per_slot", obj->id ) );
     153             : 
     154           0 :   return obj;
     155           0 : }
     156             : 
     157             : void
     158             : setup_topo_vinyl_meta( fd_topo_t *    topo,
     159           0 :                        fd_configf_t * config ) {
     160           0 :   fd_topob_wksp( topo, "vinyl_meta" );
     161             : 
     162           0 :   fd_topo_obj_t * map_obj = fd_topob_obj( topo, "vinyl_meta", "vinyl_meta" );
     163           0 :   ulong const meta_max  = fd_ulong_pow2_up( config->vinyl.max_account_records );
     164           0 :   ulong const lock_cnt  = fd_vinyl_meta_lock_cnt_est ( meta_max );
     165           0 :   ulong const probe_max = fd_vinyl_meta_probe_max_est( meta_max );
     166           0 :   fd_pod_insertf_ulong( topo->props, meta_max,  "obj.%lu.ele_max",   map_obj->id );
     167           0 :   fd_pod_insertf_ulong( topo->props, lock_cnt,  "obj.%lu.lock_cnt",  map_obj->id );
     168           0 :   fd_pod_insertf_ulong( topo->props, probe_max, "obj.%lu.probe_max", map_obj->id );
     169           0 :   fd_pod_insertf_ulong( topo->props, (ulong)fd_tickcount(), "obj.%lu.seed", map_obj->id );
     170             : 
     171           0 :   fd_topo_obj_t * meta_pool_obj = fd_topob_obj( topo, "vinyl_meta_e", "vinyl_meta" );
     172           0 :   fd_pod_insertf_ulong( topo->props, meta_max, "obj.%lu.cnt", meta_pool_obj->id );
     173             : 
     174           0 :   fd_pod_insert_ulong( topo->props, "vinyl.meta_map",  map_obj->id );
     175           0 :   fd_pod_insert_ulong( topo->props, "vinyl.meta_pool", meta_pool_obj->id );
     176           0 : }
     177             : 
     178             : fd_topo_obj_t *
     179             : setup_topo_vinyl_cache( fd_topo_t *    topo,
     180           0 :                         fd_configf_t * config ) {
     181           0 :   fd_topob_wksp( topo, "vinyl_data" );
     182           0 :   fd_topo_obj_t * line_obj = fd_topob_obj( topo, "vinyl_data", "vinyl_data" );
     183           0 :   ulong const heap_max = config->vinyl.cache_size_gib<<30;
     184           0 :   fd_pod_insertf_ulong( topo->props, heap_max, "obj.%lu.data_sz", line_obj->id );
     185           0 :   fd_pod_insert_ulong( topo->props, "vinyl.data", line_obj->id );
     186           0 :   return line_obj;
     187           0 : }
     188             : 
     189             : /* Resolves a hostname to a single ip address.  If multiple ip address
     190             :    records are returned by getaddrinfo, only the first IPV4 address is
     191             :    returned via ip_addr. */
     192             : static int
     193             : resolve_address( char const * address,
     194           0 :                  uint       * ip_addr ) {
     195           0 :   struct addrinfo hints = { .ai_family = AF_INET };
     196           0 :   struct addrinfo * res;
     197           0 :   int err = getaddrinfo( address, NULL, &hints, &res );
     198           0 :   if( FD_UNLIKELY( err ) ) {
     199           0 :     FD_LOG_WARNING(( "cannot resolve address \"%s\": %i-%s", address, err, gai_strerror( err ) ));
     200           0 :     return 0;
     201           0 :   }
     202             : 
     203           0 :   int resolved = 0;
     204           0 :   for( struct addrinfo * cur=res; cur; cur=cur->ai_next ) {
     205           0 :     if( FD_UNLIKELY( cur->ai_addr->sa_family!=AF_INET ) ) continue;
     206           0 :     struct sockaddr_in const * addr = (struct sockaddr_in const *)cur->ai_addr;
     207           0 :     *ip_addr = addr->sin_addr.s_addr;
     208           0 :     resolved = 1;
     209           0 :     break;
     210           0 :   }
     211             : 
     212           0 :   freeaddrinfo( res );
     213           0 :   return resolved;
     214           0 : }
     215             : 
     216             : /* Resolves a hostname to multiple ip addresses, specified by
     217             :    ip_addr_cnt.  ip_addrs points to an array of fd_ip4_port_t objects.
     218             :    hints points to an optionally NULL addrinfo hints object.  If hints
     219             :    is NULL, a default hints settings containing the IPV4 address family
     220             :    hint will be used. */
     221             : static int
     222             : resolve_addresses( char const *             address,
     223             :                    struct addrinfo const *  hints,
     224             :                    fd_ip4_port_t *          ip_addrs,
     225           0 :                    ulong                    ip_addr_cnt ) {
     226           0 :   struct addrinfo default_hints = { .ai_family = AF_INET };
     227           0 :   if( FD_UNLIKELY( !hints ) ) {
     228           0 :     hints = &default_hints;
     229           0 :   }
     230             : 
     231           0 :   struct addrinfo * res;
     232           0 :   int err = getaddrinfo( address, NULL, hints, &res );
     233           0 :   if( FD_UNLIKELY( err ) ) {
     234           0 :     FD_LOG_WARNING(( "cannot resolve address \"%s\": %i-%s", address, err, gai_strerror( err ) ));
     235           0 :     return 0;
     236           0 :   }
     237             : 
     238           0 :   int resolved = 0;
     239           0 :   for( struct addrinfo * cur=res; cur; cur=cur->ai_next ) {
     240           0 :     if( FD_UNLIKELY( (ulong)resolved>=ip_addr_cnt ) ) break;
     241           0 :     if( FD_UNLIKELY( cur->ai_addr->sa_family!=AF_INET ) ) continue;
     242           0 :     struct sockaddr_in const * addr = (struct sockaddr_in const *)cur->ai_addr;
     243           0 :     ip_addrs[ resolved ].addr = addr->sin_addr.s_addr;
     244           0 :     resolved++;
     245           0 :   }
     246             : 
     247           0 :   freeaddrinfo( res );
     248           0 :   return resolved;
     249           0 : }
     250             : 
     251             : static int
     252             : resolve_peer( char const *            peer,
     253             :               struct addrinfo const * addr_resolve_hints,
     254             :               char const *            config_str,
     255             :               char                    hostname[ static 256UL ],
     256             :               fd_ip4_port_t *         ip4_port,
     257             :               ulong                   ip4_port_cnt,
     258           0 :               int *                   is_https ) {
     259             : 
     260             :   /* Split host:port */
     261           0 :   int          https     = 0;
     262           0 :   char const * host_port = peer;
     263           0 :   if( FD_LIKELY( strncmp( peer, "http://", 7UL )==0 ) ) {
     264           0 :     if( FD_LIKELY( is_https ) ) *is_https  = 0;
     265           0 :     host_port += 7UL;
     266           0 :   } else if( FD_LIKELY( strncmp( peer, "https://", 8UL )==0 ) ) {
     267           0 :     if( FD_LIKELY( is_https ) ) *is_https  = 1;
     268           0 :     host_port += 8UL;
     269           0 :     https      = 1;
     270           0 :   }
     271             : 
     272           0 :   char const * colon    = strrchr( host_port, ':' );
     273           0 :   char const * host_end = colon;
     274           0 :   if( FD_UNLIKELY( !colon && !https ) ) {
     275           0 :     FD_LOG_ERR(( "invalid [%s] entry \"%s\": no port number", config_str, host_port ));
     276           0 :   } else if( FD_LIKELY( !colon && https ) ) {
     277           0 :     host_end = host_port + strlen( host_port );
     278           0 :   }
     279             : 
     280           0 :   ulong fqdn_len = (ulong)( host_end-host_port );
     281           0 :   if( FD_UNLIKELY( fqdn_len>255 ) ) {
     282           0 :     FD_LOG_ERR(( "invalid [%s] entry \"%s\": hostname too long", config_str, host_port ));
     283           0 :   }
     284           0 :   fd_memcpy( hostname, host_port, fqdn_len );
     285           0 :   hostname[ fqdn_len ] = '\0';
     286             : 
     287             :   /* Resolve hostname */
     288           0 :   int resolved = resolve_addresses( hostname, addr_resolve_hints, ip4_port, ip4_port_cnt );
     289             : 
     290             :   /* Parse port number */
     291             : 
     292           0 :   if( FD_LIKELY( colon ) ) {
     293           0 :     char const * port_str = host_end+1;
     294           0 :     char const * endptr   = NULL;
     295           0 :     ulong port = strtoul( port_str, (char **)&endptr, 10 );
     296           0 :     if( FD_UNLIKELY( endptr==port_str || !port || port>USHORT_MAX || *endptr!='\0' ) ) {
     297           0 :       FD_LOG_ERR(( "invalid [%s] entry \"%s\": invalid port number", config_str, host_port ));
     298           0 :     }
     299           0 :     for( ulong i=0UL; i<(ulong)resolved; i++ ) ip4_port[ i ].port = fd_ushort_bswap( (ushort)port );
     300           0 :   } else if( FD_LIKELY( !colon && https ) ) {
     301             :     /* use default https port */
     302           0 :     for( ulong i=0UL; i<(ulong)resolved; i++ ) ip4_port[ i ].port = fd_ushort_bswap( 443U );
     303           0 :   } else {
     304           0 :     FD_LOG_ERR(( "invalid [%s] entry \"%s\": no port number", config_str, host_port ));
     305           0 :   }
     306             : 
     307           0 :   return resolved;
     308           0 : }
     309             : 
     310             : static void
     311           0 : resolve_gossip_entrypoints( config_t * config ) {
     312           0 :   ulong entrypoint_cnt = config->gossip.entrypoints_cnt;
     313           0 :   for( ulong i=0UL; i<entrypoint_cnt; i++ ) {
     314           0 :     char hostname[ 256UL ];
     315           0 :     if( FD_UNLIKELY( 0==resolve_peer( config->gossip.entrypoints[ i ], NULL, "gossip.entrypoints", hostname, &config->gossip.resolved_entrypoints[ i ], 1, NULL ) ) ) {
     316           0 :       FD_LOG_ERR(( "failed to resolve address of [gossip.entrypoints] entry \"%s\"", config->gossip.entrypoints[ i ] ));
     317           0 :     }
     318           0 :   }
     319           0 : }
     320             : 
     321             : void
     322           0 : fd_topo_initialize( config_t * config ) {
     323             :   /* TODO: Not here ... */
     324           0 :   resolve_gossip_entrypoints( config );
     325             : 
     326           0 :   ulong net_tile_cnt    = config->layout.net_tile_count;
     327           0 :   ulong shred_tile_cnt  = config->layout.shred_tile_count;
     328           0 :   ulong quic_tile_cnt   = config->layout.quic_tile_count;
     329           0 :   ulong verify_tile_cnt = config->layout.verify_tile_count;
     330           0 :   ulong resolv_tile_cnt = config->layout.resolv_tile_count;
     331           0 :   ulong bank_tile_cnt   = config->layout.bank_tile_count;
     332             : 
     333           0 :   ulong gossvf_tile_cnt = config->firedancer.layout.gossvf_tile_count;
     334           0 :   ulong exec_tile_cnt   = config->firedancer.layout.exec_tile_count;
     335           0 :   ulong sign_tile_cnt   = config->firedancer.layout.sign_tile_count;
     336           0 :   ulong lta_tile_cnt    = config->firedancer.layout.snapla_tile_count;
     337             : 
     338           0 :   int snapshots_enabled = !!config->gossip.entrypoints_cnt;
     339           0 :   int vinyl_enabled     = !!config->firedancer.vinyl.enabled;
     340           0 :   int snapshot_lthash_disabled = config->development.snapshots.disable_lthash_verification;
     341             : 
     342           0 :   fd_topo_t * topo = fd_topob_new( &config->topo, config->name );
     343             : 
     344           0 :   topo->max_page_size = fd_cstr_to_shmem_page_sz( config->hugetlbfs.max_page_size );
     345           0 :   topo->gigantic_page_threshold = config->hugetlbfs.gigantic_page_threshold_mib << 20;
     346             : 
     347             :   /*             topo, name */
     348           0 :   fd_topob_wksp( topo, "metric"       );
     349           0 :   fd_topob_wksp( topo, "genesi"       );
     350           0 :   fd_topob_wksp( topo, "ipecho"       );
     351           0 :   fd_topob_wksp( topo, "gossvf"       );
     352           0 :   fd_topob_wksp( topo, "gossip"       );
     353           0 :   fd_topob_wksp( topo, "shred"        );
     354           0 :   fd_topob_wksp( topo, "repair"       );
     355           0 :   fd_topob_wksp( topo, "replay"       );
     356           0 :   fd_topob_wksp( topo, "exec"         );
     357           0 :   fd_topob_wksp( topo, "tower"        );
     358           0 :   fd_topob_wksp( topo, "send"         );
     359             : 
     360           0 :   fd_topob_wksp( topo, "quic"         );
     361           0 :   fd_topob_wksp( topo, "verify"       );
     362           0 :   fd_topob_wksp( topo, "dedup"        );
     363           0 :   fd_topob_wksp( topo, "resolv"       );
     364           0 :   fd_topob_wksp( topo, "pack"         );
     365           0 :   fd_topob_wksp( topo, "bank"         );
     366           0 :   fd_topob_wksp( topo, "poh"          );
     367           0 :   fd_topob_wksp( topo, "sign"         );
     368             : 
     369           0 :   fd_topob_wksp( topo, "metric_in"    );
     370             : 
     371           0 :   fd_topob_wksp( topo, "net_gossip"   );
     372           0 :   fd_topob_wksp( topo, "net_shred"    );
     373           0 :   fd_topob_wksp( topo, "net_repair"   );
     374           0 :   fd_topob_wksp( topo, "net_send"     );
     375           0 :   fd_topob_wksp( topo, "net_quic"     );
     376             : 
     377           0 :   fd_topob_wksp( topo, "genesi_out"   );
     378           0 :   fd_topob_wksp( topo, "ipecho_out"   );
     379           0 :   fd_topob_wksp( topo, "gossvf_gossi" );
     380           0 :   fd_topob_wksp( topo, "gossip_gossv" );
     381           0 :   fd_topob_wksp( topo, "gossip_out"   );
     382             : 
     383           0 :   fd_topob_wksp( topo, "shred_out"    );
     384           0 :   fd_topob_wksp( topo, "replay_stake" );
     385           0 :   fd_topob_wksp( topo, "replay_exec"  );
     386           0 :   fd_topob_wksp( topo, "replay_out"   );
     387           0 :   fd_topob_wksp( topo, "tower_out"    );
     388           0 :   fd_topob_wksp( topo, "send_out"     );
     389             : 
     390           0 :   fd_topob_wksp( topo, "quic_verify"  );
     391           0 :   fd_topob_wksp( topo, "verify_dedup" );
     392           0 :   fd_topob_wksp( topo, "dedup_resolv" );
     393           0 :   fd_topob_wksp( topo, "resolv_pack"  );
     394           0 :   fd_topob_wksp( topo, "pack_poh"     );
     395           0 :   fd_topob_wksp( topo, "pack_bank"    );
     396           0 :   fd_topob_wksp( topo, "resolv_repla" );
     397           0 :   if( FD_LIKELY( config->tiles.pack.use_consumed_cus ) ) {
     398           0 :     fd_topob_wksp( topo, "bank_pack"  );
     399           0 :   }
     400           0 :   fd_topob_wksp( topo, "bank_poh"     );
     401           0 :   fd_topob_wksp( topo, "bank_busy"    );
     402           0 :   fd_topob_wksp( topo, "poh_shred"    );
     403           0 :   fd_topob_wksp( topo, "poh_replay"   );
     404             : 
     405           0 :   fd_topob_wksp( topo, "funk"         );
     406           0 :   fd_topob_wksp( topo, "progcache"    );
     407           0 :   fd_topob_wksp( topo, "fec_sets"     );
     408           0 :   fd_topob_wksp( topo, "txncache"     );
     409           0 :   fd_topob_wksp( topo, "banks"        );
     410           0 :   fd_topob_wksp( topo, "store"        );
     411           0 :   fd_topob_wksp( topo, "executed_txn" );
     412             : 
     413           0 :   fd_topob_wksp( topo, "gossip_sign"  );
     414           0 :   fd_topob_wksp( topo, "sign_gossip"  );
     415             : 
     416           0 :   fd_topob_wksp( topo, "shred_sign"   );
     417           0 :   fd_topob_wksp( topo, "sign_shred"   );
     418             : 
     419           0 :   fd_topob_wksp( topo, "repair_sign"  );
     420           0 :   fd_topob_wksp( topo, "sign_repair"  );
     421             : 
     422           0 :   fd_topob_wksp( topo, "send_sign"    );
     423           0 :   fd_topob_wksp( topo, "sign_send"    );
     424             : 
     425           0 :   fd_topob_wksp( topo, "exec_sig"     );
     426             : 
     427           0 :   fd_topob_wksp( topo, "cswtch"       );
     428             : 
     429           0 :   fd_topob_wksp( topo, "exec_replay"  );
     430             : 
     431           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
     432           0 :     fd_topob_wksp( topo, "snapct"      );
     433           0 :     fd_topob_wksp( topo, "snapld"      );
     434           0 :     fd_topob_wksp( topo, "snapdc"      );
     435           0 :     fd_topob_wksp( topo, "snapin"      );
     436           0 :     if( vinyl_enabled ) {
     437           0 :       fd_topob_wksp( topo, "snapwh" );
     438           0 :       fd_topob_wksp( topo, "snapwr" );
     439           0 :     }
     440             : 
     441           0 :     fd_topob_wksp( topo, "snapct_ld"   );
     442           0 :     fd_topob_wksp( topo, "snapld_dc"   );
     443           0 :     fd_topob_wksp( topo, "snapdc_in"   );
     444           0 :     if( vinyl_enabled ) fd_topob_wksp( topo, "snapin_wr" );
     445             : 
     446           0 :     if( FD_UNLIKELY( snapshot_lthash_disabled ) ) {
     447           0 :       fd_topob_wksp( topo, "snapin_ct" );
     448           0 :     } else {
     449           0 :       fd_topob_wksp( topo, "snapls_ct" );
     450           0 :     }
     451             : 
     452           0 :     if( FD_LIKELY( config->tiles.gui.enabled ) ) fd_topob_wksp( topo, "snapct_gui"  );
     453           0 :     if( FD_LIKELY( config->tiles.gui.enabled ) ) fd_topob_wksp( topo, "snapin_gui"  );
     454           0 :     fd_topob_wksp( topo, "snapin_manif" );
     455           0 :     fd_topob_wksp( topo, "snapct_repr"  );
     456             : 
     457           0 :     if( FD_LIKELY( !snapshot_lthash_disabled ) ) {
     458           0 :       fd_topob_wksp( topo, "snapla"    );
     459           0 :       fd_topob_wksp( topo, "snapls"    );
     460           0 :       fd_topob_wksp( topo, "snapla_ls" );
     461           0 :       fd_topob_wksp( topo, "snapin_ls" );
     462           0 :     }
     463           0 :   }
     464             : 
     465           0 :   #define FOR(cnt) for( ulong i=0UL; i<cnt; i++ )
     466             : 
     467           0 :   ulong shred_depth = 65536UL; /* from fdctl/topology.c shred_store link. MAKE SURE TO KEEP IN SYNC. */
     468             : 
     469             :   /*                                  topo, link_name,      wksp_name,      depth,                                    mtu,                           burst */
     470           0 :   /**/                 fd_topob_link( topo, "gossip_net",   "net_gossip",   32768UL,                                  FD_NET_MTU,                    1UL );
     471           0 :   FOR(shred_tile_cnt)  fd_topob_link( topo, "shred_net",    "net_shred",    32768UL,                                  FD_NET_MTU,                    1UL );
     472           0 :   /**/                 fd_topob_link( topo, "repair_net",   "net_repair",   config->net.ingress_buffer_size,          FD_NET_MTU,                    1UL );
     473           0 :   /**/                 fd_topob_link( topo, "send_net",     "net_send",     config->net.ingress_buffer_size,          FD_NET_MTU,                    1UL );
     474           0 :   FOR(quic_tile_cnt)   fd_topob_link( topo, "quic_net",     "net_quic",     config->net.ingress_buffer_size,          FD_NET_MTU,                    1UL );
     475             : 
     476           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
     477             :   /* TODO: Revisit the depths of all the snapshot links */
     478           0 :     /**/               fd_topob_link( topo, "snapct_ld",    "snapct_ld",    128UL,                                    sizeof(fd_ssctrl_init_t),      1UL );
     479           0 :     /**/               fd_topob_link( topo, "snapld_dc",    "snapld_dc",    16384UL,                                  USHORT_MAX,                    1UL );
     480           0 :     /**/               fd_topob_link( topo, "snapdc_in",    "snapdc_in",    16384UL,                                  USHORT_MAX,                    1UL );
     481           0 :     if( FD_UNLIKELY( snapshot_lthash_disabled ) ) {
     482           0 :                        fd_topob_link( topo, "snapin_ct",    "snapin_ct",    128UL,                                    0UL,                           1UL );
     483           0 :     } else {
     484           0 :                        fd_topob_link( topo, "snapls_ct",    "snapls_ct",    128UL,                                    0UL,                           1UL );
     485           0 :     }
     486           0 :     /**/               fd_topob_link( topo, "snapin_manif", "snapin_manif", 4UL,                                      sizeof(fd_snapshot_manifest_t),1UL );
     487           0 :     /**/               fd_topob_link( topo, "snapct_repr",  "snapct_repr",  128UL,                                    0UL,                           1UL )->permit_no_consumers = 1; /* TODO: wire in repair later */
     488           0 :     if( FD_LIKELY( config->tiles.gui.enabled ) ) {
     489           0 :       /**/             fd_topob_link( topo, "snapct_gui",   "snapct_gui",   128UL,                                    sizeof(fd_snapct_update_t),    1UL );
     490           0 :       /**/             fd_topob_link( topo, "snapin_gui",   "snapin_gui",   128UL,                                    FD_GUI_CONFIG_PARSE_MAX_VALID_ACCT_SZ_WITH_NULL, 1UL );
     491           0 :     }
     492           0 :     if( vinyl_enabled ) {
     493           0 :       fd_topo_link_t * snapin_wh =
     494           0 :       /**/             fd_topob_link( topo, "snapin_wh",    "snapin_wr",    4UL,                                      16UL<<20,                      1UL );
     495           0 :       /**/             fd_topob_link( topo, "snapwh_wr",    "snapin_wr",    4UL,                                      0UL,                           1UL );
     496           0 :       fd_pod_insertf_ulong( topo->props, 8UL, "obj.%lu.app_sz",  snapin_wh->dcache_obj_id );
     497           0 :     }
     498           0 :     if( FD_LIKELY( !snapshot_lthash_disabled ) ) {
     499           0 :     FOR(lta_tile_cnt) fd_topob_link( topo,  "snapla_ls",    "snapla_ls",    128UL,                                    sizeof(fd_lthash_value_t),     1UL );
     500           0 :     /**/              fd_topob_link( topo,  "snapin_ls",    "snapin_ls",    256UL,                                    sizeof(fd_snapshot_full_account_t), 1UL );
     501           0 :     }
     502           0 :   }
     503             : 
     504             :   /**/                 fd_topob_link( topo, "genesi_out",   "genesi_out",   2UL,                                      10UL*1024UL*1024UL+32UL+sizeof(fd_lthash_value_t), 1UL );
     505           0 :   /**/                 fd_topob_link( topo, "ipecho_out",   "ipecho_out",   2UL,                                      0UL,                           1UL );
     506           0 :   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 );
     507           0 :   /**/                 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 */
     508           0 :   /**/                 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 */
     509             : 
     510           0 :   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 );
     511           0 :   FOR(verify_tile_cnt) fd_topob_link( topo, "verify_dedup", "verify_dedup", config->tiles.verify.receive_buffer_size, FD_TPU_PARSED_MTU,             1UL );
     512           0 :   /**/                 fd_topob_link( topo, "dedup_resolv", "dedup_resolv", 65536UL,                                  FD_TPU_PARSED_MTU,             1UL );
     513           0 :   FOR(resolv_tile_cnt) fd_topob_link( topo, "resolv_pack",  "resolv_pack",  65536UL,                                  FD_TPU_RESOLVED_MTU,           1UL );
     514           0 :   /**/                 fd_topob_link( topo, "replay_stake", "replay_stake", 128UL,                                    FD_STAKE_OUT_MTU,              1UL ); /* TODO: This should be 2 but requires fixing STEM_BURST */
     515           0 :   /**/                 fd_topob_link( topo, "replay_out",   "replay_out",   8192UL,                                   sizeof(fd_replay_message_t),   1UL );
     516           0 :   /**/                 fd_topob_link( topo, "pack_poh",     "pack_poh",     4096UL,                                   sizeof(fd_done_packing_t),     1UL );
     517             :   /* pack_bank is shared across all banks, so if one bank stalls due to complex transactions, the buffer needs to be large so that
     518             :      other banks can keep proceeding. */
     519           0 :   /**/                 fd_topob_link( topo, "pack_bank",    "pack_bank",    65536UL,                                  USHORT_MAX,                    1UL );
     520           0 :   FOR(bank_tile_cnt)   fd_topob_link( topo, "bank_poh",     "bank_poh",     16384UL,                                  USHORT_MAX,                    1UL );
     521           0 :   if( FD_LIKELY( config->tiles.pack.use_consumed_cus ) ) {
     522           0 :     FOR(bank_tile_cnt) fd_topob_link( topo, "bank_pack",    "bank_pack",    16384UL,                                  USHORT_MAX,                    1UL );
     523           0 :   }
     524           0 :   /**/                 fd_topob_link( topo, "poh_shred",    "poh_shred",    16384UL,                                  USHORT_MAX,                    1UL );
     525           0 :   /**/                 fd_topob_link( topo, "poh_replay",   "poh_replay",   4096UL,                                   sizeof(fd_poh_leader_slot_ended_t), 1UL );
     526           0 :   FOR(resolv_tile_cnt) fd_topob_link( topo, "resolv_repla", "resolv_repla", 4096UL,                                   sizeof(fd_resolv_slot_exchanged_t), 1UL );
     527           0 :   /**/                 fd_topob_link( topo, "executed_txn", "executed_txn", 16384UL,                                  64UL,                          1UL ); /* TODO: Rename this ... */
     528             : 
     529           0 :   FOR(shred_tile_cnt)  fd_topob_link( topo, "shred_sign",   "shred_sign",   128UL,                                    32UL,                          1UL );
     530           0 :   FOR(shred_tile_cnt)  fd_topob_link( topo, "sign_shred",   "sign_shred",   128UL,                                    sizeof(fd_ed25519_sig_t),      1UL );
     531             : 
     532             :   /**/                 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 */
     533           0 :   /**/                 fd_topob_link( topo, "sign_gossip",  "sign_gossip",  128UL,                                    sizeof(fd_ed25519_sig_t),      1UL ); /* TODO: Depth probably doesn't need to be 128 */
     534             : 
     535           0 :   FOR(sign_tile_cnt-1) fd_topob_link( topo, "repair_sign",  "repair_sign",  128UL,                                    FD_REPAIR_MAX_PREIMAGE_SZ,     1UL );
     536           0 :   FOR(sign_tile_cnt-1) fd_topob_link( topo, "sign_repair",  "sign_repair",  128UL,                                    sizeof(fd_ed25519_sig_t),      1UL );
     537             : 
     538           0 :   /**/                 fd_topob_link( topo, "send_sign",    "send_sign",    128UL,                                    FD_TXN_MTU,                    1UL ); /* TODO: Depth probably doesn't need to be 128 */
     539           0 :   /**/                 fd_topob_link( topo, "sign_send",    "sign_send",    128UL,                                    sizeof(fd_ed25519_sig_t),      1UL ); /* TODO: Depth probably doesn't need to be 128 */
     540             : 
     541           0 :   FOR(shred_tile_cnt)  fd_topob_link( topo, "shred_out",    "shred_out",    shred_depth,                              FD_SHRED_OUT_MTU,              3UL ); /* TODO: Pretty sure burst of 3 is incorrect here */
     542           0 :   FOR(shred_tile_cnt)  fd_topob_link( topo, "repair_shred", "shred_out",    shred_depth,                              sizeof(fd_ed25519_sig_t),      1UL );
     543           0 :   /**/                 fd_topob_link( topo, "tower_out",    "tower_out",    128UL,                                    sizeof(fd_tower_msg_t),        3UL ); /* dup conf + cluster conf + slot_done */
     544           0 :   /**/                 fd_topob_link( topo, "send_out",     "send_out",     128UL,                                    FD_TPU_RAW_MTU,                1UL );
     545             : 
     546           0 :                        fd_topob_link( topo, "replay_exec",  "replay_exec",  16384UL,                                  sizeof(fd_exec_task_msg_t),    1UL );
     547             : 
     548           0 :   FOR(exec_tile_cnt)   fd_topob_link( topo, "exec_sig",     "exec_sig",     16384UL,                                  64UL,                          1UL );
     549           0 :   FOR(exec_tile_cnt)   fd_topob_link( topo, "exec_replay",  "exec_replay",  16384UL,                                  sizeof(fd_exec_task_done_msg_t), 1UL );
     550             : 
     551           0 :   ushort parsed_tile_to_cpu[ FD_TILE_MAX ];
     552             :   /* Unassigned tiles will be floating, unless auto topology is enabled. */
     553           0 :   for( ulong i=0UL; i<FD_TILE_MAX; i++ ) parsed_tile_to_cpu[ i ] = USHORT_MAX;
     554             : 
     555           0 :   int is_auto_affinity = !strcmp( config->layout.affinity, "auto" );
     556             : 
     557           0 :   fd_topo_cpus_t cpus[1];
     558           0 :   fd_topo_cpus_init( cpus );
     559             : 
     560           0 :   ulong affinity_tile_cnt = 0UL;
     561           0 :   if( FD_LIKELY( !is_auto_affinity ) ) affinity_tile_cnt = fd_tile_private_cpus_parse( config->layout.affinity, parsed_tile_to_cpu );
     562             : 
     563           0 :   ulong tile_to_cpu[ FD_TILE_MAX ] = {0};
     564           0 :   for( ulong i=0UL; i<affinity_tile_cnt; i++ ) {
     565           0 :     if( FD_UNLIKELY( parsed_tile_to_cpu[ i ]!=USHORT_MAX && parsed_tile_to_cpu[ i ]>=cpus->cpu_cnt ) )
     566           0 :       FD_LOG_ERR(( "The CPU affinity string in the configuration file under [layout.affinity] specifies a CPU index of %hu, but the system "
     567           0 :                    "only has %lu CPUs. You should either change the CPU allocations in the affinity string, or increase the number of CPUs "
     568           0 :                    "in the system.",
     569           0 :                    parsed_tile_to_cpu[ i ], cpus->cpu_cnt ));
     570           0 :     tile_to_cpu[ i ] = fd_ulong_if( parsed_tile_to_cpu[ i ]==USHORT_MAX, ULONG_MAX, (ulong)parsed_tile_to_cpu[ i ] );
     571           0 :   }
     572             : 
     573           0 :   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 );
     574             : 
     575           0 :   FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_gossvf", i, config->net.ingress_buffer_size );
     576           0 :   FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_shred",  i, config->net.ingress_buffer_size );
     577           0 :   FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_repair", i, config->net.ingress_buffer_size );
     578           0 :   FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_send",   i, config->net.ingress_buffer_size );
     579           0 :   FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_quic",   i, config->net.ingress_buffer_size );
     580             : 
     581             :   /*                                  topo, tile_name, tile_wksp, metrics_wksp, cpu_idx,                       is_agave, uses_keyswitch */
     582             :   /**/                 fd_topob_tile( topo, "metric",  "metric",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 );
     583           0 :   /**/                 fd_topob_tile( topo, "cswtch",  "cswtch",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 );
     584             : 
     585           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
     586           0 :     /**/               fd_topob_tile( topo, "snapct", "snapct", "metric_in", tile_to_cpu[ topo->tile_cnt ],    0,        0 )->allow_shutdown = 1;
     587           0 :     /**/               fd_topob_tile( topo, "snapld", "snapld", "metric_in", tile_to_cpu[ topo->tile_cnt ],    0,        0 )->allow_shutdown = 1;
     588           0 :     /**/               fd_topob_tile( topo, "snapdc", "snapdc", "metric_in", tile_to_cpu[ topo->tile_cnt ],    0,        0 )->allow_shutdown = 1;
     589           0 :     /**/               fd_topob_tile( topo, "snapin", "snapin", "metric_in", tile_to_cpu[ topo->tile_cnt ],    0,        0 )->allow_shutdown = 1;
     590           0 :     if(vinyl_enabled)  fd_topob_tile( topo, "snapwh", "snapwh", "metric_in", tile_to_cpu[ topo->tile_cnt ],    0,        0 )->allow_shutdown = 1;
     591           0 :     if(vinyl_enabled)  fd_topob_tile( topo, "snapwr", "snapwr", "metric_in", tile_to_cpu[ topo->tile_cnt ],    0,        0 )->allow_shutdown = 1;
     592             : 
     593           0 :     if( FD_LIKELY( !snapshot_lthash_disabled ) ) {
     594           0 :     FOR(lta_tile_cnt)  fd_topob_tile( topo, "snapla", "snapla", "metric_in", tile_to_cpu[ topo->tile_cnt ],  0,        0 )->allow_shutdown = 1;
     595           0 :     /**/               fd_topob_tile( topo, "snapls", "snapls", "metric_in", tile_to_cpu[ topo->tile_cnt ],  0,        0 )->allow_shutdown = 1;
     596           0 :     }
     597           0 :   }
     598             : 
     599             :   /**/                 fd_topob_tile( topo, "genesi",  "genesi",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 )->allow_shutdown = 1;
     600           0 :   /**/                 fd_topob_tile( topo, "ipecho",  "ipecho",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 );
     601           0 :   FOR(gossvf_tile_cnt) fd_topob_tile( topo, "gossvf",  "gossvf",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        1 );
     602           0 :   /**/                 fd_topob_tile( topo, "gossip",  "gossip",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        1 );
     603             : 
     604           0 :   FOR(shred_tile_cnt)  fd_topob_tile( topo, "shred",   "shred",   "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        1 );
     605           0 :   /**/                 fd_topob_tile( topo, "repair",  "repair",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 ); /* TODO: Wrong? Needs to use keyswitch as signs */
     606           0 :   /**/                 fd_topob_tile( topo, "replay",  "replay",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 );
     607           0 :   FOR(exec_tile_cnt)   fd_topob_tile( topo, "exec",    "exec",    "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 );
     608           0 :   /**/                 fd_topob_tile( topo, "tower",   "tower",   "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 );
     609           0 :   /**/                 fd_topob_tile( topo, "send",    "send",    "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 );
     610             : 
     611           0 :   FOR(quic_tile_cnt)   fd_topob_tile( topo, "quic",    "quic",    "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 );
     612           0 :   FOR(verify_tile_cnt) fd_topob_tile( topo, "verify",  "verify",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 );
     613           0 :   /**/                 fd_topob_tile( topo, "dedup",   "dedup",   "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 );
     614           0 :   FOR(resolv_tile_cnt) fd_topob_tile( topo, "resolv",  "resolv",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 );
     615           0 :   FOR(resolv_tile_cnt) strncpy( topo->tiles[ topo->tile_cnt-1UL-i ].metrics_name, "resolf", 8UL );
     616           0 :   /**/                 fd_topob_tile( topo, "pack",    "pack",    "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        config->tiles.bundle.enabled );
     617           0 :   FOR(bank_tile_cnt)   fd_topob_tile( topo, "bank",    "bank",    "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        0 );
     618           0 :   FOR(bank_tile_cnt)   strncpy( topo->tiles[ topo->tile_cnt-1UL-i ].metrics_name, "bankf", 6UL );
     619           0 :   /**/                 fd_topob_tile( topo, "poh",     "poh",     "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        1 );
     620           0 :   FOR(sign_tile_cnt)   fd_topob_tile( topo, "sign",    "sign",    "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,        1 );
     621             : 
     622             :   /*                                        topo, tile_name, tile_kind_id, fseq_wksp,   link_name,      link_kind_id, reliable,            polled */
     623           0 :   FOR(gossvf_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
     624           0 :                       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 */
     625           0 :   FOR(shred_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
     626           0 :                       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 */
     627           0 :   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 */
     628           0 :   /**/                fd_topob_tile_out(    topo, "repair",  0UL,                       "repair_net",   0UL                                                );
     629           0 :   FOR(net_tile_cnt)   fd_topob_tile_in (    topo, "send",    0UL,          "metric_in", "net_send",     i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
     630           0 :   FOR(quic_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
     631           0 :                       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 */
     632             : 
     633           0 :   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 */
     634           0 :   /**/                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 */
     635           0 :   /**/                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 */
     636           0 :   /**/                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 */
     637           0 :   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 */
     638             : 
     639           0 :   /**/                 fd_topob_tile_out(   topo, "genesi", 0UL,                        "genesi_out",   0UL                                                );
     640           0 :   /**/                 fd_topob_tile_in (   topo, "ipecho", 0UL,           "metric_in", "genesi_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     641           0 :   /**/                 fd_topob_tile_out(   topo, "ipecho", 0UL,                        "ipecho_out",   0UL                                                );
     642             : 
     643           0 :   FOR(gossvf_tile_cnt) fd_topob_tile_out(   topo, "gossvf", i,                          "gossvf_gossi", i                                                  );
     644           0 :   FOR(gossvf_tile_cnt) fd_topob_tile_in (   topo, "gossvf", i,             "metric_in", "gossip_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     645           0 :   FOR(gossvf_tile_cnt) fd_topob_tile_in (   topo, "gossvf", i,             "metric_in", "gossip_gossv", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     646           0 :   FOR(gossvf_tile_cnt) fd_topob_tile_in (   topo, "gossvf", i,             "metric_in", "ipecho_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     647           0 :   FOR(gossvf_tile_cnt) fd_topob_tile_in (   topo, "gossvf", i,             "metric_in", "replay_stake", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     648           0 :   /**/                 fd_topob_tile_in (   topo, "gossip", 0UL,           "metric_in", "replay_stake", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     649           0 :   /**/                 fd_topob_tile_out(   topo, "gossip", 0UL,                        "gossip_out",   0UL                                                );
     650           0 :   /**/                 fd_topob_tile_out(   topo, "gossip", 0UL,                        "gossip_net",   0UL                                                );
     651           0 :   /**/                 fd_topob_tile_in (   topo, "gossip", 0UL,           "metric_in", "ipecho_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     652           0 :   FOR(gossvf_tile_cnt) fd_topob_tile_in (   topo, "gossip", 0UL,           "metric_in", "gossvf_gossi", i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
     653           0 :   /**/                 fd_topob_tile_in(    topo, "gossip", 0UL,           "metric_in", "send_out",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     654           0 :   /**/                 fd_topob_tile_out(   topo, "gossip", 0UL,                        "gossip_gossv", 0UL                                                );
     655             : 
     656           0 :   int snapshots_gossip_enabled = config->firedancer.snapshots.sources.gossip.allow_any || config->firedancer.snapshots.sources.gossip.allow_list_cnt>0UL;
     657           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
     658           0 :     if( FD_LIKELY( snapshots_gossip_enabled ) ) {
     659           0 :       /**/            fd_topob_tile_in (    topo, "snapct",  0UL,          "metric_in", "gossip_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     660           0 :     }
     661             : 
     662           0 :     if( FD_UNLIKELY( snapshot_lthash_disabled ) ) {
     663           0 :                       fd_topob_tile_in (    topo, "snapct",  0UL,          "metric_in", "snapin_ct",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     664           0 :     } else {
     665           0 :                       fd_topob_tile_in (    topo, "snapct",  0UL,          "metric_in", "snapls_ct",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     666           0 :     }
     667           0 :                       fd_topob_tile_in (    topo, "snapct",  0UL,          "metric_in", "snapld_dc",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     668           0 :                       fd_topob_tile_out(    topo, "snapct",  0UL,                       "snapct_ld",    0UL                                                );
     669           0 :                       fd_topob_tile_out(    topo, "snapct",  0UL,                       "snapct_repr",  0UL                                                );
     670           0 :     if( FD_LIKELY( config->tiles.gui.enabled ) ) {
     671           0 :       /**/            fd_topob_tile_out(    topo, "snapct",  0UL,                       "snapct_gui",   0UL                                                );
     672           0 :     }
     673           0 :     if( vinyl_enabled ) {
     674           0 :       /**/            fd_topob_tile_out(    topo, "snapin",  0UL,                       "snapin_wh",    0UL                                                );
     675           0 :       /**/            fd_topob_tile_in (    topo, "snapwh",  0UL,          "metric_in", "snapin_wh",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     676           0 :       /**/            fd_topob_tile_out(    topo, "snapwh",  0UL,                       "snapwh_wr",    0UL                                                );
     677           0 :       /**/            fd_topob_tile_in (    topo, "snapwr",  0UL,          "metric_in", "snapwh_wr",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     678           0 :       fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapwr", 0UL ) ], &topo->objs[ topo->links[ fd_topo_find_link( topo, "snapin_wh", 0UL ) ].dcache_obj_id ], FD_SHMEM_JOIN_MODE_READ_ONLY );
     679           0 :     }
     680             : 
     681           0 :     /**/              fd_topob_tile_in (    topo, "snapld",  0UL,          "metric_in", "snapct_ld",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     682           0 :     /**/              fd_topob_tile_out(    topo, "snapld",  0UL,                       "snapld_dc",    0UL                                                );
     683             : 
     684           0 :     /**/              fd_topob_tile_in (    topo, "snapdc",  0UL,          "metric_in", "snapld_dc",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     685           0 :     /**/              fd_topob_tile_out(    topo, "snapdc",  0UL,                       "snapdc_in",    0UL                                                );
     686             : 
     687           0 :                       fd_topob_tile_in (    topo, "snapin",  0UL,          "metric_in", "snapdc_in",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     688           0 :     if( FD_LIKELY( config->tiles.gui.enabled ) ) {
     689           0 :       /**/            fd_topob_tile_out(    topo, "snapin", 0UL,                        "snapin_gui",   0UL                                                );
     690           0 :     }
     691           0 :     if( FD_UNLIKELY( snapshot_lthash_disabled ) ) {
     692           0 :                       fd_topob_tile_out(    topo, "snapin",  0UL,                       "snapin_ct",    0UL                                                );
     693           0 :     } else {
     694           0 :                       fd_topob_tile_out(    topo, "snapin",  0UL,                       "snapin_ls",    0UL                                                );
     695           0 :     }
     696           0 :                       fd_topob_tile_out(    topo, "snapin",  0UL,                       "snapin_manif", 0UL                                                );
     697           0 :     if( FD_LIKELY( !snapshot_lthash_disabled ) ) {
     698           0 :     FOR(lta_tile_cnt) fd_topob_tile_in(     topo, "snapla",  i,            "metric_in", "snapdc_in",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     699           0 :     FOR(lta_tile_cnt) fd_topob_tile_out(    topo, "snapla",  i,                         "snapla_ls",    i                                                  );
     700           0 :     /**/              fd_topob_tile_in(     topo, "snapls",  0UL,          "metric_in", "snapin_ls",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     701           0 :     FOR(lta_tile_cnt) fd_topob_tile_in(     topo, "snapls",  0UL,          "metric_in", "snapla_ls",    i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     702           0 :     /**/              fd_topob_tile_out(    topo, "snapls",  0UL,                       "snapls_ct",    0UL                                                );
     703           0 :     }
     704           0 :   }
     705             : 
     706           0 :   /**/                 fd_topob_tile_in(    topo, "repair",  0UL,          "metric_in", "genesi_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     707           0 :   /**/                 fd_topob_tile_in(    topo, "repair",  0UL,          "metric_in", "gossip_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     708           0 :   /**/                 fd_topob_tile_in(    topo, "repair",  0UL,          "metric_in", "tower_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     709           0 :   /**/                 fd_topob_tile_in(    topo, "repair",  0UL,          "metric_in", "replay_stake", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     710           0 :   if( snapshots_enabled ) {
     711           0 :                        fd_topob_tile_in(    topo, "repair",  0UL,          "metric_in", "snapin_manif", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     712           0 :   }
     713           0 :   FOR(shred_tile_cnt)  fd_topob_tile_in(    topo, "repair",  0UL,          "metric_in", "shred_out",    i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     714           0 :   FOR(shred_tile_cnt)  fd_topob_tile_in(    topo, "replay",  0UL,          "metric_in", "shred_out",    i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     715           0 :   FOR(shred_tile_cnt)  fd_topob_tile_out(   topo, "repair",  0UL,                       "repair_shred", i                                                  );
     716           0 :   /**/                 fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "genesi_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     717           0 :   /**/                 fd_topob_tile_out(   topo, "replay",  0UL,                       "replay_out",   0UL                                                );
     718           0 :   /**/                 fd_topob_tile_out(   topo, "replay",  0UL,                       "replay_stake", 0UL                                                );
     719           0 :   /**/                 fd_topob_tile_out(   topo, "replay",  0UL,                       "executed_txn", 0UL                                                );
     720           0 :   /**/                 fd_topob_tile_out(   topo, "replay",  0UL,                       "replay_exec",  0UL                                                );
     721           0 :   /**/                 fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "tower_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     722           0 :   /**/                 fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "send_out",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     723           0 :   FOR(resolv_tile_cnt) fd_topob_tile_in(    topo, "replay",  0UL,          "metric_in", "resolv_repla", i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     724           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
     725           0 :                        fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "snapin_manif", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     726           0 :   }
     727             : 
     728           0 :   /**/                 fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "poh_replay",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     729           0 :   FOR(exec_tile_cnt)   fd_topob_tile_in (   topo, "exec",    i,            "metric_in", "replay_exec",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     730             : 
     731           0 :   /**/                 fd_topob_tile_in (   topo, "tower",   0UL,          "metric_in", "dedup_resolv", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     732           0 :   /**/                 fd_topob_tile_in (   topo, "tower",   0UL,          "metric_in", "replay_exec",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     733           0 :   /**/                 fd_topob_tile_in (   topo, "tower",   0UL,          "metric_in", "replay_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     734           0 :   /**/                 fd_topob_tile_out(   topo, "tower",   0UL,                       "tower_out",    0UL                                                );
     735             : 
     736           0 :   /**/                 fd_topob_tile_in (   topo, "send",    0UL,          "metric_in", "replay_stake", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     737           0 :   /**/                 fd_topob_tile_in (   topo, "send",    0UL,          "metric_in", "gossip_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     738           0 :   /**/                 fd_topob_tile_in (   topo, "send",    0UL,          "metric_in", "tower_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     739           0 :   /**/                 fd_topob_tile_out(   topo, "send",    0UL,                       "send_net",     0UL                                                );
     740           0 :   /**/                 fd_topob_tile_out(   topo, "send",    0UL,                       "send_out",     0UL                                                );
     741             : 
     742           0 :   FOR(quic_tile_cnt)  fd_topob_tile_out(    topo, "quic",    i,                         "quic_verify",  i                                                  );
     743           0 :   FOR(quic_tile_cnt)  fd_topob_tile_out(    topo, "quic",    i,                         "quic_net",     i                                                  );
     744             :   /* All verify tiles read from all QUIC tiles, packets are round robin. */
     745           0 :   FOR(verify_tile_cnt) for( ulong j=0UL; j<quic_tile_cnt; j++ )
     746           0 :                        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 */
     747           0 :   FOR(verify_tile_cnt) fd_topob_tile_in(    topo, "verify",  i,            "metric_in", "gossip_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     748           0 :   /**/                 fd_topob_tile_in(    topo, "verify",  0UL,          "metric_in", "send_out",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     749           0 :   FOR(verify_tile_cnt) fd_topob_tile_out(   topo, "verify",  i,                         "verify_dedup", i                                                  );
     750           0 :   FOR(verify_tile_cnt) fd_topob_tile_in(    topo, "dedup",   0UL,          "metric_in", "verify_dedup", i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     751           0 :   /**/                 fd_topob_tile_in(    topo, "dedup",   0UL,          "metric_in", "executed_txn", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     752           0 :   /**/                 fd_topob_tile_out(   topo, "dedup",   0UL,                       "dedup_resolv", 0UL                                                );
     753           0 :   FOR(resolv_tile_cnt) fd_topob_tile_in(    topo, "resolv",  i,            "metric_in", "dedup_resolv", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     754           0 :   FOR(resolv_tile_cnt) fd_topob_tile_in(    topo, "resolv",  i,            "metric_in", "replay_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     755           0 :   FOR(resolv_tile_cnt) fd_topob_tile_out(   topo, "resolv",  i,                         "resolv_pack",  i                                                  );
     756           0 :   FOR(resolv_tile_cnt) fd_topob_tile_out(   topo, "resolv",  i,                         "resolv_repla", i                                                  );
     757           0 :   /**/                 fd_topob_tile_in(    topo, "pack",    0UL,          "metric_in", "resolv_pack",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     758           0 :   /**/                 fd_topob_tile_in(    topo, "pack",    0UL,          "metric_in", "replay_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     759           0 :   /**/                 fd_topob_tile_in(    topo, "pack",    0UL,          "metric_in", "executed_txn", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     760           0 :                        fd_topob_tile_out(   topo, "pack",    0UL,                       "pack_bank",    0UL                                                );
     761           0 :                        fd_topob_tile_out(   topo, "pack",    0UL,                       "pack_poh" ,    0UL                                                );
     762           0 :   if( FD_LIKELY( config->tiles.pack.use_consumed_cus ) ) {
     763           0 :     FOR(bank_tile_cnt) fd_topob_tile_in(    topo, "pack",    0UL,          "metric_in", "bank_pack",    i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     764           0 :   }
     765           0 :   FOR(bank_tile_cnt)   fd_topob_tile_in(    topo, "bank",    i,            "metric_in", "pack_bank",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     766           0 :   FOR(bank_tile_cnt)   fd_topob_tile_out(   topo, "bank",    i,                         "bank_poh",     i                                                  );
     767           0 :   if( FD_LIKELY( config->tiles.pack.use_consumed_cus ) ) {
     768           0 :     FOR(bank_tile_cnt) fd_topob_tile_out(   topo, "bank",    i,                         "bank_pack",    i                                                  );
     769           0 :   }
     770           0 :   FOR(bank_tile_cnt)   fd_topob_tile_in(    topo, "poh",     0UL,          "metric_in", "bank_poh",     i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     771           0 :   /**/                 fd_topob_tile_in(    topo, "poh",     0UL,          "metric_in", "pack_poh",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     772           0 :   /**/                 fd_topob_tile_in(    topo, "poh",     0UL,          "metric_in", "replay_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     773           0 :   /**/                 fd_topob_tile_out(   topo, "poh",     0UL,                       "poh_shred",    0UL                                                );
     774           0 :   /**/                 fd_topob_tile_out(   topo, "poh",     0UL,                       "poh_replay",   0UL                                                );
     775           0 :   FOR(shred_tile_cnt)  fd_topob_tile_in (   topo, "shred",   i,            "metric_in", "replay_stake", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     776           0 :   FOR(shred_tile_cnt)  fd_topob_tile_in (   topo, "shred",   i,            "metric_in", "gossip_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     777           0 :   FOR(shred_tile_cnt)  fd_topob_tile_out(   topo, "shred",   i,                         "shred_out",    i                                                  );
     778           0 :   FOR(shred_tile_cnt)  fd_topob_tile_in (   topo, "shred",   i,            "metric_in", "repair_shred", i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     779           0 :   FOR(shred_tile_cnt)  fd_topob_tile_in (   topo, "shred",   i,            "metric_in", "ipecho_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     780           0 :   FOR(shred_tile_cnt)  fd_topob_tile_in (   topo, "shred",   i,            "metric_in", "poh_shred",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     781           0 :   FOR(shred_tile_cnt)  fd_topob_tile_out(   topo, "shred",   i,                         "shred_net",    i                                                  );
     782             : 
     783           0 :   FOR(exec_tile_cnt)   fd_topob_tile_in (   topo, "dedup",   0UL,          "metric_in", "exec_sig",     i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     784           0 :   FOR(exec_tile_cnt)   fd_topob_tile_in (   topo, "pack",    0UL,          "metric_in", "exec_sig",     i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     785           0 :   FOR(exec_tile_cnt)   fd_topob_tile_out(   topo, "exec",    i,                         "exec_sig",     i                                                  );
     786           0 :   FOR(exec_tile_cnt)   fd_topob_tile_out(   topo, "exec",    i,                         "exec_replay",  i                                                  );
     787           0 :   FOR(exec_tile_cnt)   fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "exec_replay",  i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     788             : 
     789             : 
     790           0 :   if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
     791           0 :     fd_topob_wksp( topo, "bundle_verif" );
     792           0 :     fd_topob_wksp( topo, "bundle_sign"  );
     793           0 :     fd_topob_wksp( topo, "sign_bundle"  );
     794           0 :     fd_topob_wksp( topo, "pack_sign"    );
     795           0 :     fd_topob_wksp( topo, "sign_pack"    );
     796           0 :     fd_topob_wksp( topo, "bundle"       );
     797             : 
     798           0 :     /**/                 fd_topob_link( topo, "bundle_verif", "bundle_verif", config->tiles.verify.receive_buffer_size, FD_TPU_PARSED_MTU,         1UL );
     799           0 :     /**/                 fd_topob_link( topo, "bundle_sign",  "bundle_sign",  65536UL,                                  9UL,                       1UL );
     800           0 :     /**/                 fd_topob_link( topo, "sign_bundle",  "sign_bundle",  128UL,                                    64UL,                      1UL );
     801           0 :     /**/                 fd_topob_link( topo, "pack_sign",    "pack_sign",    65536UL,                                  1232UL,                    1UL );
     802           0 :     /**/                 fd_topob_link( topo, "sign_pack",    "sign_pack",    128UL,                                    64UL,                      1UL );
     803             : 
     804             :     /**/                 fd_topob_tile( topo, "bundle",  "bundle",  "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
     805             : 
     806             :     /**/                 fd_topob_tile_out( topo, "bundle", 0UL, "bundle_verif", 0UL );
     807           0 :     FOR(verify_tile_cnt) fd_topob_tile_in(  topo, "verify", i,             "metric_in", "bundle_verif",   0UL,        FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
     808             : 
     809           0 :     /**/                 fd_topob_tile_in(  topo, "sign",   0UL,           "metric_in", "bundle_sign",    0UL,        FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     810           0 :     /**/                 fd_topob_tile_out( topo, "bundle", 0UL,                        "bundle_sign",    0UL                                                );
     811           0 :     /**/                 fd_topob_tile_in(  topo, "bundle", 0UL,           "metric_in", "sign_bundle",    0UL,        FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
     812           0 :     /**/                 fd_topob_tile_out( topo, "sign",   0UL,                        "sign_bundle",    0UL                                                );
     813             : 
     814           0 :     /**/                 fd_topob_tile_in(  topo, "sign",   0UL,           "metric_in", "pack_sign",      0UL,        FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     815           0 :     /**/                 fd_topob_tile_out( topo, "pack",   0UL,                        "pack_sign",      0UL                                                );
     816           0 :     /**/                 fd_topob_tile_in(  topo, "pack",   0UL,           "metric_in", "sign_pack",      0UL,        FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
     817           0 :     /**/                 fd_topob_tile_out( topo, "sign",   0UL,                        "sign_pack",      0UL                                                );
     818             : 
     819             :     /* TODO: bundle gui support needs to be integrated here */
     820           0 :   }
     821             : 
     822             :   /* Sign links don't need to be reliable because they are synchronous,
     823             :      so there's at most one fragment in flight at a time anyway.  The
     824             :      sign links are also not polled by fd_stem, instead the tiles will
     825             :      read the sign responses out of band in a dedicated spin loop.
     826             : 
     827             :      TODO: This can probably be fixed now to be relible ... ? */
     828             :   /*                                        topo, tile_name, tile_kind_id, fseq_wksp,   link_name,      link_kind_id, reliable,            polled */
     829           0 :   /**/                 fd_topob_tile_in (   topo, "sign",    0UL,          "metric_in", "gossip_sign",  0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     830           0 :   /**/                 fd_topob_tile_out(   topo, "gossip",  0UL,                       "gossip_sign",  0UL                                                  );
     831           0 :   /**/                 fd_topob_tile_in (   topo, "gossip",  0UL,          "metric_in", "sign_gossip",  0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
     832           0 :   /**/                 fd_topob_tile_out(   topo, "sign",    0UL,                       "sign_gossip",  0UL                                                  );
     833             : 
     834           0 :   for( ulong i=0UL; i<shred_tile_cnt; i++ ) {
     835           0 :     /**/               fd_topob_tile_in (   topo, "sign",    0UL,          "metric_in", "shred_sign",   i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     836           0 :     /**/               fd_topob_tile_out(   topo, "shred",   i,                         "shred_sign",   i                                                    );
     837           0 :     /**/               fd_topob_tile_in (   topo, "shred",   i,            "metric_in", "sign_shred",   i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
     838           0 :     /**/               fd_topob_tile_out(   topo, "sign",    0UL,                       "sign_shred",   i                                                    );
     839           0 :   }
     840             : 
     841           0 :   FOR(sign_tile_cnt-1UL) fd_topob_tile_out( topo, "repair",  0UL,                       "repair_sign",  i                                                    );
     842           0 :   FOR(sign_tile_cnt-1UL) fd_topob_tile_in ( topo, "sign",    i+1UL,        "metric_in", "repair_sign",  i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
     843           0 :   FOR(sign_tile_cnt-1UL) fd_topob_tile_out( topo, "sign",    i+1UL,                     "sign_repair",  i                                                    );
     844           0 :   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 */
     845             : 
     846           0 :   /**/                 fd_topob_tile_in (   topo, "sign",    0UL,          "metric_in", "send_sign",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
     847           0 :   /**/                 fd_topob_tile_out(   topo, "send",    0UL,                       "send_sign",    0UL                                                  );
     848           0 :   /**/                 fd_topob_tile_in (   topo, "send",    0UL,          "metric_in", "sign_send",    0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
     849           0 :   /**/                 fd_topob_tile_out(   topo, "sign",    0UL,                       "sign_send",    0UL                                                  );
     850             : 
     851           0 :   if( FD_UNLIKELY( config->tiles.archiver.enabled ) ) {
     852           0 :     fd_topob_wksp( topo, "arch_f" );
     853           0 :     fd_topob_wksp( topo, "arch_w" );
     854           0 :     fd_topob_wksp( topo, "feeder" );
     855           0 :     fd_topob_wksp( topo, "arch_f2w" );
     856             : 
     857           0 :     fd_topob_link( topo, "feeder", "feeder", 65536UL, 4UL*FD_SHRED_STORE_MTU, 4UL+config->tiles.shred.max_pending_shred_sets );
     858           0 :     fd_topob_link( topo, "arch_f2w", "arch_f2w", 128UL, 4UL*FD_SHRED_STORE_MTU, 1UL );
     859             : 
     860           0 :     fd_topob_tile( topo, "arch_f", "arch_f", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
     861           0 :     fd_topob_tile( topo, "arch_w", "arch_w", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
     862             : 
     863           0 :     fd_topob_tile_out( topo, "replay", 0UL,              "feeder", 0UL );
     864           0 :     fd_topob_tile_in(  topo, "arch_f", 0UL, "metric_in", "feeder", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     865             : 
     866           0 :     fd_topob_tile_out( topo, "arch_f", 0UL,              "arch_f2w", 0UL );
     867           0 :     fd_topob_tile_in(  topo, "arch_w", 0UL, "metric_in", "arch_f2w", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     868           0 :   }
     869             : 
     870           0 :   if( FD_UNLIKELY( config->tiles.shredcap.enabled ) ) {
     871           0 :     fd_topob_wksp( topo, "scap" );
     872             : 
     873           0 :     fd_topob_tile( topo, "scap", "scap", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0 );
     874             : 
     875           0 :     fd_topob_tile_in(  topo, "scap", 0UL, "metric_in", "repair_net", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
     876           0 :     for( ulong j=0UL; j<net_tile_cnt; j++ ) {
     877           0 :       fd_topob_tile_in(  topo, "scap", 0UL, "metric_in", "net_shred", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
     878           0 :     }
     879           0 :     for( ulong j=0UL; j<shred_tile_cnt; j++ ) {
     880           0 :       fd_topob_tile_in(  topo, "scap", 0UL, "metric_in", "shred_out", j, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
     881           0 :     }
     882           0 :     fd_topob_tile_in( topo, "scap", 0UL, "metric_in", "gossip_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     883             : 
     884           0 :     fd_topob_tile_in( topo, "scap", 0UL, "metric_in", "replay_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     885             : 
     886             :     /* No default fd_topob_tile_in connection to stake_out */
     887           0 :   }
     888             : 
     889           0 :   int rpc_enabled = config->tiles.rpc.enabled;
     890           0 :   if( FD_UNLIKELY( rpc_enabled ) ) {
     891           0 :     fd_topob_wksp( topo, "rpc" );
     892           0 :     fd_topob_wksp( topo, "rpc_replay" );
     893           0 :     fd_topob_link( topo, "rpc_replay", "rpc_replay", 4UL, 0UL, 1UL );
     894           0 :     fd_topob_tile( topo, "rpc",  "rpc",  "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 1 );
     895           0 :     fd_topob_tile_out( topo, "rpc", 0UL, "rpc_replay", 0UL );
     896           0 :     fd_topob_tile_in( topo, "rpc",  0UL, "metric_in", "replay_out",  0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     897           0 :     fd_topob_tile_in( topo, "rpc",  0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     898           0 :     fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "rpc_replay", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     899           0 :   }
     900             : 
     901           0 :   if( FD_LIKELY( !is_auto_affinity ) ) {
     902           0 :     if( FD_UNLIKELY( affinity_tile_cnt<topo->tile_cnt ) )
     903           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. "
     904           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 "
     905           0 :                    "the total tile count. You can reduce the tile count by decreasing individual tile counts in the [layout] section of the configuration file.",
     906           0 :                    topo->tile_cnt, affinity_tile_cnt ));
     907           0 :     if( FD_UNLIKELY( affinity_tile_cnt>topo->tile_cnt ) )
     908           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. "
     909           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 "
     910           0 :                        "individual tile counts in the [layout] section of the configuration file.",
     911           0 :                        topo->tile_cnt, affinity_tile_cnt ));
     912           0 :   }
     913             : 
     914             : 
     915           0 :   if( FD_UNLIKELY( is_auto_affinity ) ) fd_topob_auto_layout( topo, 0 );
     916             : 
     917             :   /* There is a special fseq that sits between the pack, bank, and poh
     918             :      tiles to indicate when the bank/poh tiles are done processing a
     919             :      microblock.  Pack uses this to determine when to "unlock" accounts
     920             :      that it marked as locked because they were being used. */
     921             : 
     922           0 :   for( ulong i=0UL; i<bank_tile_cnt; i++ ) {
     923           0 :     fd_topo_obj_t * busy_obj = fd_topob_obj( topo, "fseq", "bank_busy" );
     924             : 
     925           0 :     fd_topo_tile_t * pack_tile = &topo->tiles[ fd_topo_find_tile( topo, "pack", 0UL ) ];
     926           0 :     fd_topo_tile_t * bank_tile = &topo->tiles[ fd_topo_find_tile( topo, "bank", i ) ];
     927           0 :     fd_topob_tile_uses( topo, pack_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
     928           0 :     fd_topob_tile_uses( topo, bank_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     929           0 :     FD_TEST( fd_pod_insertf_ulong( topo->props, busy_obj->id, "bank_busy.%lu", i ) );
     930           0 :   }
     931             : 
     932           0 :   fd_topo_obj_t * funk_obj = setup_topo_funk( topo, "funk",
     933           0 :       config->firedancer.funk.max_account_records,
     934           0 :       config->firedancer.funk.max_database_transactions,
     935           0 :       config->firedancer.funk.heap_size_gib );
     936           0 :   /**/                 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? */
     937           0 :   /**/                 fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "tower", 0UL  ) ], funk_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
     938           0 :   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 );
     939           0 :   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 );
     940           0 :   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  );
     941             : 
     942           0 :   fd_topo_obj_t * banks_obj = setup_topo_banks( topo, "banks", config->firedancer.runtime.max_live_slots, config->firedancer.runtime.max_fork_width, config->development.bench.larger_max_cost_per_block );
     943           0 :   /**/                 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? */
     944           0 :   /**/                 fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "tower",  0UL ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     945           0 :   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? */
     946           0 :   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 );
     947           0 :   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  );
     948           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, banks_obj->id, "banks" ) );
     949             : 
     950           0 :   fd_topo_obj_t * progcache_obj = setup_topo_progcache( topo, "progcache",
     951           0 :       fd_progcache_est_rec_max( config->firedancer.runtime.program_cache.heap_size_mib<<20,
     952           0 :                                 config->firedancer.runtime.program_cache.mean_cache_entry_size ),
     953           0 :       config->firedancer.funk.max_database_transactions,
     954           0 :       config->firedancer.runtime.program_cache.heap_size_mib<<20 );
     955           0 :   /**/                 fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], progcache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     956           0 :   FOR(exec_tile_cnt)   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "exec",   i   ) ], progcache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     957           0 :   FOR(bank_tile_cnt)   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "bank",   i   ) ], progcache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     958             : 
     959           0 :   if( FD_LIKELY( config->tiles.gui.enabled ) ) {
     960           0 :     fd_topob_wksp( topo, "gui" );
     961             : 
     962             :     /**/                 fd_topob_tile(     topo, "gui",     "gui",     "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0, 1 );
     963             : 
     964             :     /* Read banks */
     965             :     /* TODO: SECURITY CRITICAL. GUI SHOULD NOT HAVE WRITE ACCESS TO BANKS, JUST HACKED IN FOR NOW SO RWLOCK WORKS */
     966           0 :     /**/                 fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "gui", 0UL ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     967             : 
     968             :     /* release ownership of banks */
     969             :     /**/                 fd_topob_link( topo, "gui_replay", "gui", 128, 0UL,2UL ); /* burst==2 since a bank and its parent may be sent in one burst */
     970             : 
     971           0 :     /**/                 fd_topob_tile_out( topo, "gui",    0UL,                        "gui_replay", 0UL                                                );
     972           0 :     /**/                 fd_topob_tile_in ( topo, "replay", 0UL,           "metric_in", "gui_replay", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     973             : 
     974             :     /*                                      topo, tile_name, tile_kind_id, fseq_wksp,   link_name,      link_kind_id, reliable,            polled */
     975           0 :     FOR(net_tile_cnt)    fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "net_gossvf",   i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
     976           0 :     /**/                 fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "repair_net",   0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
     977           0 :     FOR(shred_tile_cnt)  fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "shred_out",    i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     978           0 :     /**/                 fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "gossip_net",   0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
     979           0 :     /**/                 fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "gossip_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     980           0 :     /**/                 fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "tower_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     981           0 :     /**/                 fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "replay_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     982           0 :     /**/                 fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "replay_stake", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     983           0 :     /**/                 fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "genesi_out",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     984           0 :     /**/                 fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "pack_poh",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     985           0 :     /**/                 fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "pack_bank",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     986           0 :     FOR(bank_tile_cnt)   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "bank_poh",       i,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     987           0 :     FOR(exec_tile_cnt)   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "exec_replay",    i,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     988             : 
     989           0 :     if( FD_LIKELY( snapshots_enabled ) ) {
     990           0 :     /**/                 fd_topob_tile_in ( topo, "gui",    0UL,           "metric_in", "snapct_gui",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     991           0 :     /**/                 fd_topob_tile_in ( topo, "gui",    0UL,           "metric_in", "snapin_gui",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     992           0 :     }
     993           0 :   }
     994             : 
     995           0 :   ulong fec_set_cnt = shred_depth + config->tiles.shred.max_pending_shred_sets + 4UL;
     996           0 :   ulong fec_sets_sz = fec_set_cnt*sizeof(fd_shred34_t)*4; /* mirrors # of dcache entires in frankendancer */
     997           0 :   fd_topo_obj_t * fec_sets_obj = setup_topo_fec_sets( topo, "fec_sets", shred_tile_cnt*fec_sets_sz );
     998           0 :   for( ulong i=0UL; i<shred_tile_cnt; i++ ) {
     999           0 :     fd_topo_tile_t * shred_tile = &topo->tiles[ fd_topo_find_tile( topo, "shred", i ) ];
    1000           0 :     fd_topob_tile_uses( topo, shred_tile, fec_sets_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1001           0 :   }
    1002           0 :   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "repair", 0UL ) ], fec_sets_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
    1003           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, fec_sets_obj->id, "fec_sets" ) );
    1004             : 
    1005           0 :   fd_topo_obj_t * store_obj = setup_topo_store( topo, "store", config->firedancer.store.max_completed_shred_sets, (uint)shred_tile_cnt );
    1006           0 :   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 );
    1007           0 :   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1008           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, store_obj->id, "store" ) );
    1009             : 
    1010           0 :   fd_topo_obj_t * txncache_obj = setup_topo_txncache( topo, "txncache",
    1011           0 :       config->firedancer.runtime.max_live_slots,
    1012           0 :       fd_ulong_pow2_up( FD_PACK_MAX_TXNCACHE_TXN_PER_SLOT ) );
    1013           0 :   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1014           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
    1015           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapin", 0UL ) ], txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1016           0 :   }
    1017           0 :   FOR(bank_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "bank", i ) ], txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1018           0 :   FOR(exec_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "exec", i ) ], txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1019           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, txncache_obj->id, "txncache" ) );
    1020             : 
    1021           0 :   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "genesi", 0UL ) ], funk_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1022           0 :   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 );
    1023             : 
    1024           0 :   if( FD_UNLIKELY( rpc_enabled ) ) {
    1025           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "rpcsrv", 0UL ) ], funk_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1026           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "rpcsrv", 0UL ) ], store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1027           0 :   }
    1028             : 
    1029           0 :   fd_pod_insert_int( topo->props, "sandbox", config->development.sandbox ? 1 : 0 );
    1030             : 
    1031           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) fd_topo_configure_tile( &topo->tiles[ i ], config );
    1032             : 
    1033           0 :   FOR(net_tile_cnt) fd_topos_net_tile_finish( topo, i );
    1034           0 :   fd_topob_finish( topo, CALLBACKS );
    1035           0 :   config->topo = *topo;
    1036           0 : }
    1037             : 
    1038             : void
    1039             : fd_topo_configure_tile( fd_topo_tile_t * tile,
    1040           0 :                         fd_config_t *    config ) {
    1041           0 :   if( FD_UNLIKELY( !strcmp( tile->name, "metric" ) ) ) {
    1042             : 
    1043           0 :     if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.metric.prometheus_listen_address, &tile->metric.prometheus_listen_addr ) ) )
    1044           0 :       FD_LOG_ERR(( "failed to parse prometheus listen address `%s`", config->tiles.metric.prometheus_listen_address ));
    1045           0 :     tile->metric.prometheus_listen_port = config->tiles.metric.prometheus_listen_port;
    1046             : 
    1047           0 :   } else  if( FD_UNLIKELY( !strcmp( tile->name, "net" ) || !strcmp( tile->name, "sock" ) ) ) {
    1048             : 
    1049           0 :     tile->net.shred_listen_port              = config->tiles.shred.shred_listen_port;
    1050           0 :     tile->net.quic_transaction_listen_port   = config->tiles.quic.quic_transaction_listen_port;
    1051           0 :     tile->net.legacy_transaction_listen_port = config->tiles.quic.regular_transaction_listen_port;
    1052           0 :     tile->net.gossip_listen_port             = config->gossip.port;
    1053           0 :     tile->net.repair_intake_listen_port      = config->tiles.repair.repair_intake_listen_port;
    1054           0 :     tile->net.repair_serve_listen_port       = config->tiles.repair.repair_serve_listen_port;
    1055           0 :     tile->net.send_src_port                  = config->tiles.send.send_src_port;
    1056             : 
    1057           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "netlnk" ) ) ) {
    1058             : 
    1059           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "ipecho") ) ) {
    1060             : 
    1061           0 :     tile->ipecho.expected_shred_version = config->consensus.expected_shred_version;
    1062           0 :     tile->ipecho.bind_address           = config->net.ip_addr;
    1063           0 :     tile->ipecho.bind_port              = config->gossip.port;
    1064           0 :     tile->ipecho.entrypoints_cnt        = config->gossip.entrypoints_cnt;
    1065           0 :     fd_memcpy( tile->ipecho.entrypoints, config->gossip.resolved_entrypoints, tile->ipecho.entrypoints_cnt * sizeof(fd_ip4_port_t) );
    1066             : 
    1067           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "genesi" ) ) ) {
    1068             : 
    1069           0 :     tile->genesi.funk_obj_id = fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX );
    1070             : 
    1071           0 :     tile->genesi.allow_download = config->firedancer.snapshots.genesis_download;
    1072           0 :     strncpy( tile->genesi.genesis_path, config->paths.genesis, sizeof(tile->genesi.genesis_path) );
    1073           0 :     tile->genesi.expected_shred_version = config->consensus.expected_shred_version;
    1074           0 :     tile->genesi.entrypoints_cnt        = config->gossip.entrypoints_cnt;
    1075           0 :     fd_memcpy( tile->genesi.entrypoints, config->gossip.resolved_entrypoints, tile->genesi.entrypoints_cnt * sizeof(fd_ip4_port_t) );
    1076             : 
    1077           0 :     tile->genesi.has_expected_genesis_hash = !!strcmp( config->consensus.expected_genesis_hash, "" );
    1078             : 
    1079           0 :     if( FD_UNLIKELY( strcmp( config->consensus.expected_genesis_hash, "" ) && !fd_base58_decode_32( config->consensus.expected_genesis_hash, tile->genesi.expected_genesis_hash ) ) ) {
    1080           0 :       FD_LOG_ERR(( "failed to decode [consensus.expected_genesis_hash] \"%s\" as base58", config->consensus.expected_genesis_hash ));
    1081           0 :     }
    1082             : 
    1083           0 :     tile->genesi.target_gid = config->gid;
    1084           0 :     tile->genesi.target_uid = config->uid;
    1085             : 
    1086           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "gossvf") ) ) {
    1087             : 
    1088           0 :     strncpy( tile->gossvf.identity_key_path, config->paths.identity_key, sizeof(tile->gossvf.identity_key_path) );
    1089           0 :     tile->gossvf.tcache_depth          = 1<<22UL; /* TODO: user defined option */
    1090           0 :     tile->gossvf.shred_version         = 0U;
    1091           0 :     tile->gossvf.allow_private_address = config->development.gossip.allow_private_address;
    1092           0 :     tile->gossvf.boot_timestamp_nanos   = config->boot_timestamp_nanos;
    1093             : 
    1094           0 :     tile->gossvf.entrypoints_cnt = config->gossip.entrypoints_cnt;
    1095           0 :     fd_memcpy( tile->gossvf.entrypoints, config->gossip.resolved_entrypoints, tile->gossvf.entrypoints_cnt * sizeof(fd_ip4_port_t) );
    1096             : 
    1097           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "gossip" ) ) ) {
    1098             : 
    1099           0 :     if( FD_UNLIKELY( strcmp( config->firedancer.gossip.host, "" ) ) ) {
    1100           0 :       if( !resolve_address( config->firedancer.gossip.host, &tile->gossip.ip_addr ) )
    1101           0 :         FD_LOG_ERR(( "could not resolve [gossip.host] %s", config->firedancer.gossip.host ));
    1102           0 :     } else {
    1103           0 :       tile->gossip.ip_addr = config->net.ip_addr;
    1104           0 :     }
    1105           0 :     strncpy( tile->gossip.identity_key_path, config->paths.identity_key, sizeof(tile->gossip.identity_key_path) );
    1106           0 :     tile->gossip.shred_version       = config->consensus.expected_shred_version;
    1107           0 :     tile->gossip.max_entries         = config->tiles.gossip.max_entries;
    1108           0 :     tile->gossip.boot_timestamp_nanos = config->boot_timestamp_nanos;
    1109             : 
    1110           0 :     tile->gossip.ports.gossip           = config->gossip.port;
    1111           0 :     tile->gossip.ports.tvu              = config->tiles.shred.shred_listen_port;
    1112           0 :     tile->gossip.ports.tpu              = config->tiles.quic.regular_transaction_listen_port;
    1113           0 :     tile->gossip.ports.tpu_quic         = config->tiles.quic.quic_transaction_listen_port;
    1114           0 :     tile->gossip.ports.repair           = config->tiles.repair.repair_intake_listen_port;
    1115             : 
    1116           0 :     tile->gossip.entrypoints_cnt        = config->gossip.entrypoints_cnt;
    1117           0 :     fd_memcpy( tile->gossip.entrypoints, config->gossip.resolved_entrypoints, tile->gossip.entrypoints_cnt * sizeof(fd_ip4_port_t) );
    1118             : 
    1119           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapct" ) ) ) {
    1120             : 
    1121           0 :     fd_memcpy( tile->snapct.snapshots_path, config->paths.snapshots, PATH_MAX );
    1122           0 :     tile->snapct.sources.max_local_full_effective_age = config->firedancer.snapshots.sources.max_local_full_effective_age;
    1123           0 :     tile->snapct.sources.max_local_incremental_age    = config->firedancer.snapshots.sources.max_local_incremental_age;
    1124           0 :     tile->snapct.incremental_snapshots                = config->firedancer.snapshots.incremental_snapshots;
    1125           0 :     tile->snapct.max_full_snapshots_to_keep           = config->firedancer.snapshots.max_full_snapshots_to_keep;
    1126           0 :     tile->snapct.max_incremental_snapshots_to_keep    = config->firedancer.snapshots.max_incremental_snapshots_to_keep;
    1127           0 :     tile->snapct.full_effective_age_cancel_threshold  = config->firedancer.snapshots.full_effective_age_cancel_threshold;
    1128           0 :     tile->snapct.sources.gossip.allow_any             = config->firedancer.snapshots.sources.gossip.allow_any;
    1129           0 :     tile->snapct.sources.gossip.allow_list_cnt        = config->firedancer.snapshots.sources.gossip.allow_list_cnt;
    1130           0 :     tile->snapct.sources.gossip.block_list_cnt        = config->firedancer.snapshots.sources.gossip.block_list_cnt;
    1131           0 :     tile->snapct.sources.servers_cnt                  = config->firedancer.snapshots.sources.servers_cnt;
    1132           0 :     for( ulong i=0UL; i<tile->snapct.sources.gossip.allow_list_cnt; i++ ) {
    1133           0 :       if( FD_UNLIKELY( !fd_base58_decode_32( config->firedancer.snapshots.sources.gossip.allow_list[ i ], tile->snapct.sources.gossip.allow_list[ i ].uc ) ) ) {
    1134           0 :         FD_LOG_ERR(( "[snapshots.sources.gossip.allow_list[%lu]] invalid (%s)", i, config->firedancer.snapshots.sources.gossip.allow_list[ i ] ));
    1135           0 :       }
    1136           0 :     }
    1137           0 :     for( ulong i=0UL; i<tile->snapct.sources.gossip.block_list_cnt; i++ ) {
    1138           0 :       if( FD_UNLIKELY( !fd_base58_decode_32( config->firedancer.snapshots.sources.gossip.block_list[ i ], tile->snapct.sources.gossip.block_list[ i ].uc ) ) ) {
    1139           0 :         FD_LOG_ERR(( "[snapshots.sources.gossip.block_list[%lu]] invalid (%s)", i, config->firedancer.snapshots.sources.gossip.block_list[ i ] ));
    1140           0 :       }
    1141           0 :     }
    1142             : 
    1143           0 :     ulong resolved_peers_cnt = 0UL;
    1144           0 :     for( ulong i=0UL; i<tile->snapct.sources.servers_cnt; i++ ) {
    1145           0 :       fd_ip4_port_t resolved_addrs[ FD_TOPO_MAX_RESOLVED_ADDRS ];
    1146           0 :       struct addrinfo hints = { .ai_family = AF_INET, .ai_socktype = SOCK_STREAM };
    1147           0 :       int num_resolved = resolve_peer( config->firedancer.snapshots.sources.servers[ i ],
    1148           0 :                                        &hints,
    1149           0 :                                        "snapshots.sources.servers",
    1150           0 :                                        tile->snapct.sources.servers[ resolved_peers_cnt ].hostname,
    1151           0 :                                        resolved_addrs,
    1152           0 :                                        FD_TOPO_MAX_RESOLVED_ADDRS,
    1153           0 :                                        &tile->snapct.sources.servers[ resolved_peers_cnt ].is_https );
    1154           0 :       if( FD_UNLIKELY( 0==num_resolved ) ) {
    1155           0 :         FD_LOG_ERR(( "[snapshots.sources.servers[%lu]] invalid (%s)", i, config->firedancer.snapshots.sources.servers[ i ] ));
    1156           0 :       } else {
    1157           0 :         for( ulong i=0UL; i<(ulong)num_resolved; i++ ) tile->snapct.sources.servers[ resolved_peers_cnt+i ].addr = resolved_addrs[ i ];
    1158           0 :         for( ulong i=1UL; i<(ulong)num_resolved; i++ ) {
    1159           0 :           tile->snapct.sources.servers[ resolved_peers_cnt+i ].is_https = tile->snapct.sources.servers[ resolved_peers_cnt ].is_https;
    1160           0 :           fd_memcpy( tile->snapct.sources.servers[ resolved_peers_cnt+i ].hostname,
    1161           0 :                      tile->snapct.sources.servers[ resolved_peers_cnt ].hostname,
    1162           0 :                      sizeof(tile->snapct.sources.servers[ resolved_peers_cnt ].hostname) );
    1163           0 :         }
    1164           0 :         resolved_peers_cnt += (ulong)num_resolved;
    1165           0 :       }
    1166           0 :     }
    1167           0 :     tile->snapct.sources.servers_cnt = resolved_peers_cnt;
    1168           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapld" ) ) ) {
    1169             : 
    1170           0 :     fd_memcpy( tile->snapld.snapshots_path, config->paths.snapshots, PATH_MAX );
    1171             : 
    1172           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapdc" ) ) ) {
    1173             : 
    1174           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapin" ) ) ) {
    1175             : 
    1176           0 :     tile->snapin.max_live_slots  = config->firedancer.runtime.max_live_slots;
    1177           0 :     tile->snapin.funk_obj_id     = fd_pod_query_ulong( config->topo.props, "funk",     ULONG_MAX );
    1178           0 :     tile->snapin.txncache_obj_id = fd_pod_query_ulong( config->topo.props, "txncache", ULONG_MAX );
    1179             : 
    1180           0 :     tile->snapin.use_vinyl = !!config->firedancer.vinyl.enabled;
    1181           0 :     tile->snapin.lthash_disabled = !!config->development.snapshots.disable_lthash_verification;
    1182           0 :     if( tile->snapin.use_vinyl ) {
    1183           0 :       strcpy( tile->snapin.vinyl_path, config->paths.accounts );
    1184           0 :       tile->snapin.vinyl_meta_map_obj_id  = fd_pod_query_ulong( config->topo.props, "vinyl.meta_map",  ULONG_MAX );
    1185           0 :       tile->snapin.vinyl_meta_pool_obj_id = fd_pod_query_ulong( config->topo.props, "vinyl.meta_pool", ULONG_MAX );
    1186             : 
    1187           0 :       ulong in_wr_link_id = fd_topo_find_link( &config->topo, "snapin_wh", 0UL );
    1188           0 :       FD_TEST( in_wr_link_id!=ULONG_MAX );
    1189           0 :       fd_topo_link_t * in_wr_link = &config->topo.links[ in_wr_link_id ];
    1190           0 :       tile->snapin.snapwr_depth = in_wr_link->depth;
    1191           0 :     }
    1192             : 
    1193           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapwh" ) ) ) {
    1194             : 
    1195           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapwr" ) ) ) {
    1196             : 
    1197           0 :     strcpy( tile->snapwr.vinyl_path, config->paths.accounts );
    1198           0 :     ulong in_wr_link_id = fd_topo_find_link( &config->topo, "snapin_wh", 0UL );
    1199           0 :     FD_TEST( in_wr_link_id!=ULONG_MAX );
    1200           0 :     fd_topo_link_t * in_wr_link = &config->topo.links[ in_wr_link_id ];
    1201           0 :     tile->snapwr.dcache_obj_id = in_wr_link->dcache_obj_id;
    1202           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapla" ) ) ) {
    1203             : 
    1204           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapls" ) ) )  {
    1205             : 
    1206           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "repair" ) ) ) {
    1207           0 :     tile->repair.max_pending_shred_sets    = config->tiles.shred.max_pending_shred_sets;
    1208           0 :     tile->repair.repair_intake_listen_port = config->tiles.repair.repair_intake_listen_port;
    1209           0 :     tile->repair.repair_serve_listen_port  = config->tiles.repair.repair_serve_listen_port;
    1210           0 :     tile->repair.slot_max                  = config->tiles.repair.slot_max;
    1211           0 :     tile->repair.repair_sign_cnt           = config->firedancer.layout.sign_tile_count - 1; /* -1 because this excludes the keyguard client */
    1212           0 :     tile->repair.end_slot                  = 0;
    1213             : 
    1214           0 :     for( ulong i=0; i<tile->in_cnt; i++ ) {
    1215           0 :       if( !strcmp( config->topo.links[ tile->in_link_id[ i ] ].name, "sign_repair" ) ) {
    1216           0 :         tile->repair.repair_sign_depth = config->topo.links[ tile->in_link_id[ i ] ].depth;
    1217           0 :         break;
    1218           0 :       }
    1219           0 :     }
    1220           0 :     strncpy( tile->repair.identity_key_path, config->paths.identity_key, sizeof(tile->repair.identity_key_path) );
    1221             : 
    1222           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "replay" ) )) {
    1223             : 
    1224           0 :     if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
    1225           0 : #define PARSE_PUBKEY( _tile, f ) \
    1226           0 :       if( FD_UNLIKELY( !fd_base58_decode_32( config->tiles.bundle.f, tile->_tile.bundle.f ) ) )  \
    1227           0 :         FD_LOG_ERR(( "[tiles.bundle.enabled] set to true, but failed to parse [tiles.bundle."#f"] %s", config->tiles.bundle.f ));
    1228           0 :       tile->replay.bundle.enabled = 1;
    1229           0 :       PARSE_PUBKEY( replay, tip_distribution_program_addr );
    1230           0 :       PARSE_PUBKEY( replay, tip_payment_program_addr      );
    1231           0 :       strncpy( tile->replay.bundle.vote_account_path, config->paths.vote_account, sizeof(tile->replay.bundle.vote_account_path) );
    1232           0 :     } else {
    1233           0 :       fd_memset( &tile->replay.bundle, '\0', sizeof(tile->replay.bundle) );
    1234           0 :     }
    1235             : 
    1236           0 :     tile->replay.max_live_slots = config->firedancer.runtime.max_live_slots;
    1237           0 :     tile->replay.fec_max = config->tiles.shred.max_pending_shred_sets;
    1238           0 :     tile->replay.max_vote_accounts = config->firedancer.runtime.max_vote_accounts;
    1239             : 
    1240           0 :     tile->replay.txncache_obj_id  = fd_pod_query_ulong( config->topo.props, "txncache",  ULONG_MAX ); FD_TEST( tile->replay.txncache_obj_id !=ULONG_MAX );
    1241           0 :     tile->replay.funk_obj_id      = fd_pod_query_ulong( config->topo.props, "funk",      ULONG_MAX ); FD_TEST( tile->replay.funk_obj_id     !=ULONG_MAX );
    1242           0 :     tile->replay.progcache_obj_id = fd_pod_query_ulong( config->topo.props, "progcache", ULONG_MAX ); FD_TEST( tile->replay.progcache_obj_id!=ULONG_MAX );
    1243             : 
    1244           0 :     tile->replay.max_live_slots = config->firedancer.runtime.max_live_slots;
    1245             : 
    1246           0 :     tile->replay.expected_shred_version = config->consensus.expected_shred_version;
    1247             : 
    1248           0 :     tile->replay.larger_max_cost_per_block = config->development.bench.larger_max_cost_per_block;
    1249             : 
    1250           0 :     strncpy( tile->replay.genesis_path, config->paths.genesis, sizeof(tile->replay.genesis_path) );
    1251             : 
    1252             :     /* not specified by [tiles.replay] */
    1253             : 
    1254           0 :     strncpy( tile->replay.identity_key_path, config->paths.identity_key, sizeof(tile->replay.identity_key_path) );
    1255           0 :     tile->replay.ip_addr = config->net.ip_addr;
    1256           0 :     strncpy( tile->replay.vote_account_path, config->paths.vote_account, sizeof(tile->replay.vote_account_path) );
    1257             : 
    1258           0 :     tile->replay.capture_start_slot = config->capture.capture_start_slot;
    1259           0 :     strncpy( tile->replay.solcap_capture, config->capture.solcap_capture, sizeof(tile->replay.solcap_capture) );
    1260           0 :     strncpy( tile->replay.dump_proto_dir, config->capture.dump_proto_dir, sizeof(tile->replay.dump_proto_dir) );
    1261           0 :     tile->replay.dump_block_to_pb = config->capture.dump_block_to_pb;
    1262             : 
    1263           0 :     FD_TEST( tile->replay.funk_obj_id == fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX ) );
    1264             : 
    1265           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "exec" ) ) ) {
    1266             : 
    1267           0 :     tile->exec.funk_obj_id      = fd_pod_query_ulong( config->topo.props, "funk",      ULONG_MAX ); FD_TEST( tile->exec.funk_obj_id     !=ULONG_MAX );
    1268           0 :     tile->exec.txncache_obj_id  = fd_pod_query_ulong( config->topo.props, "txncache",  ULONG_MAX ); FD_TEST( tile->exec.txncache_obj_id !=ULONG_MAX );
    1269           0 :     tile->exec.progcache_obj_id = fd_pod_query_ulong( config->topo.props, "progcache", ULONG_MAX ); FD_TEST( tile->exec.progcache_obj_id!=ULONG_MAX );
    1270             : 
    1271           0 :     tile->exec.max_live_slots = config->firedancer.runtime.max_live_slots;
    1272             : 
    1273           0 :     tile->exec.capture_start_slot = config->capture.capture_start_slot;
    1274           0 :     strncpy( tile->exec.solcap_capture, config->capture.solcap_capture, sizeof(tile->exec.solcap_capture) );
    1275           0 :     strncpy( tile->exec.dump_proto_dir, config->capture.dump_proto_dir, sizeof(tile->exec.dump_proto_dir) );
    1276           0 :     tile->exec.dump_instr_to_pb = config->capture.dump_instr_to_pb;
    1277           0 :     tile->exec.dump_txn_to_pb = config->capture.dump_txn_to_pb;
    1278           0 :     tile->exec.dump_syscall_to_pb = config->capture.dump_syscall_to_pb;
    1279           0 :     tile->exec.dump_elf_to_pb = config->capture.dump_elf_to_pb;
    1280             : 
    1281           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "tower" ) ) ) {
    1282             : 
    1283           0 :     tile->tower.hard_fork_fatal    = config->firedancer.development.hard_fork_fatal;
    1284           0 :     tile->tower.max_live_slots     = config->firedancer.runtime.max_live_slots;
    1285           0 :     tile->tower.max_vote_lookahead = config->tiles.tower.max_vote_lookahead;
    1286           0 :     strncpy( tile->tower.identity_key, config->paths.identity_key, sizeof(tile->tower.identity_key) );
    1287           0 :     strncpy( tile->tower.vote_account, config->paths.vote_account, sizeof(tile->tower.vote_account) );
    1288           0 :     strncpy( tile->tower.base_path, config->paths.base, sizeof(tile->tower.base_path) );
    1289             : 
    1290           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "send" ) ) ) {
    1291             : 
    1292           0 :     tile->send.send_src_port = config->tiles.send.send_src_port;
    1293           0 :     tile->send.ip_addr = config->net.ip_addr;
    1294           0 :     strncpy( tile->send.identity_key_path, config->paths.identity_key, sizeof(tile->send.identity_key_path) );
    1295             : 
    1296           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "quic" ) ) ) {
    1297             : 
    1298           0 :     tile->quic.reasm_cnt                      = config->tiles.quic.txn_reassembly_count;
    1299           0 :     tile->quic.out_depth                      = config->tiles.verify.receive_buffer_size;
    1300           0 :     tile->quic.max_concurrent_connections     = config->tiles.quic.max_concurrent_connections;
    1301           0 :     tile->quic.max_concurrent_handshakes      = config->tiles.quic.max_concurrent_handshakes;
    1302           0 :     tile->quic.quic_transaction_listen_port   = config->tiles.quic.quic_transaction_listen_port;
    1303           0 :     tile->quic.idle_timeout_millis            = config->tiles.quic.idle_timeout_millis;
    1304           0 :     tile->quic.ack_delay_millis               = config->tiles.quic.ack_delay_millis;
    1305           0 :     tile->quic.retry                          = config->tiles.quic.retry;
    1306           0 :     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) ) );
    1307             : 
    1308           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "verify" ) ) ) {
    1309             : 
    1310           0 :     tile->verify.tcache_depth = config->tiles.verify.signature_cache_size;
    1311             : 
    1312           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "dedup" ) ) ) {
    1313             : 
    1314           0 :     tile->dedup.tcache_depth = config->tiles.dedup.signature_cache_size;
    1315             : 
    1316           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "resolv" ) ) ) {
    1317             : 
    1318           0 :     tile->resolv.funk_obj_id = fd_pod_query_ulong( config->topo.props, "funk", ULONG_MAX );
    1319             : 
    1320           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "pack" ) ) ) {
    1321             : 
    1322           0 :     tile->pack.max_pending_transactions      = config->tiles.pack.max_pending_transactions;
    1323           0 :     tile->pack.bank_tile_count               = config->layout.bank_tile_count;
    1324           0 :     tile->pack.larger_max_cost_per_block     = config->development.bench.larger_max_cost_per_block;
    1325           0 :     tile->pack.larger_shred_limits_per_block = config->development.bench.larger_shred_limits_per_block;
    1326           0 :     tile->pack.use_consumed_cus              = config->tiles.pack.use_consumed_cus;
    1327           0 :     tile->pack.schedule_strategy             = config->tiles.pack.schedule_strategy_enum;
    1328             : 
    1329           0 :     if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
    1330             : 
    1331           0 :       tile->pack.bundle.enabled = 1;
    1332           0 :       PARSE_PUBKEY( pack, tip_distribution_program_addr );
    1333           0 :       PARSE_PUBKEY( pack, tip_payment_program_addr      );
    1334           0 :       PARSE_PUBKEY( pack, tip_distribution_authority    );
    1335           0 :       tile->pack.bundle.commission_bps = config->tiles.bundle.commission_bps;
    1336           0 :       strncpy( tile->pack.bundle.identity_key_path, config->paths.identity_key, sizeof(tile->pack.bundle.identity_key_path) );
    1337           0 :       strncpy( tile->pack.bundle.vote_account_path, config->paths.vote_account, sizeof(tile->pack.bundle.vote_account_path) );
    1338           0 :     } else {
    1339           0 :       fd_memset( &tile->pack.bundle, '\0', sizeof(tile->pack.bundle) );
    1340           0 :     }
    1341             : 
    1342           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "bank" ) ) ) {
    1343           0 :     tile->bank.txncache_obj_id  = fd_pod_query_ulong( config->topo.props, "txncache",  ULONG_MAX );
    1344           0 :     tile->bank.funk_obj_id      = fd_pod_query_ulong( config->topo.props, "funk",      ULONG_MAX );
    1345           0 :     tile->bank.progcache_obj_id = fd_pod_query_ulong( config->topo.props, "progcache", ULONG_MAX );
    1346             : 
    1347           0 :     tile->bank.max_live_slots = config->firedancer.runtime.max_live_slots;
    1348             : 
    1349           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "poh" ) ) ) {
    1350           0 :     strncpy( tile->poh.identity_key_path, config->paths.identity_key, sizeof(tile->poh.identity_key_path) );
    1351             : 
    1352           0 :     tile->poh.plugins_enabled = 0;
    1353           0 :     tile->poh.bank_cnt = config->layout.bank_tile_count;
    1354           0 :     tile->poh.lagged_consecutive_leader_start = config->tiles.poh.lagged_consecutive_leader_start;
    1355             : 
    1356           0 :     if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
    1357           0 :       tile->poh.bundle.enabled = 1;
    1358           0 :       PARSE_PUBKEY( poh, tip_distribution_program_addr );
    1359           0 :       PARSE_PUBKEY( poh, tip_payment_program_addr      );
    1360           0 :       strncpy( tile->poh.bundle.vote_account_path, config->paths.vote_account, sizeof(tile->poh.bundle.vote_account_path) );
    1361           0 : #undef PARSE_PUBKEY
    1362           0 :     } else {
    1363           0 :       fd_memset( &tile->poh.bundle, '\0', sizeof(tile->poh.bundle) );
    1364           0 :     }
    1365             : 
    1366           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "shred" ) ) ) {
    1367             : 
    1368           0 :     strncpy( tile->shred.identity_key_path, config->paths.identity_key, sizeof(tile->shred.identity_key_path) );
    1369             : 
    1370           0 :     tile->shred.depth                         = config->topo.links[ tile->out_link_id[ 0 ] ].depth;
    1371           0 :     tile->shred.fec_resolver_depth            = config->tiles.shred.max_pending_shred_sets;
    1372           0 :     tile->shred.expected_shred_version        = config->consensus.expected_shred_version;
    1373           0 :     tile->shred.shred_listen_port             = config->tiles.shred.shred_listen_port;
    1374           0 :     tile->shred.larger_shred_limits_per_block = config->development.bench.larger_shred_limits_per_block;
    1375           0 :     for( ulong i=0UL; i<config->tiles.shred.additional_shred_destinations_retransmit_cnt; i++ ) {
    1376           0 :       parse_ip_port( "tiles.shred.additional_shred_destinations_retransmit",
    1377           0 :                       config->tiles.shred.additional_shred_destinations_retransmit[ i ],
    1378           0 :                       &tile->shred.adtl_dests_retransmit[ i ] );
    1379           0 :     }
    1380           0 :     tile->shred.adtl_dests_retransmit_cnt = config->tiles.shred.additional_shred_destinations_retransmit_cnt;
    1381           0 :     for( ulong i=0UL; i<config->tiles.shred.additional_shred_destinations_leader_cnt; i++ ) {
    1382           0 :       parse_ip_port( "tiles.shred.additional_shred_destinations_leader",
    1383           0 :                       config->tiles.shred.additional_shred_destinations_leader[ i ],
    1384           0 :                       &tile->shred.adtl_dests_leader[ i ] );
    1385           0 :     }
    1386           0 :     tile->shred.adtl_dests_leader_cnt = config->tiles.shred.additional_shred_destinations_leader_cnt;
    1387             : 
    1388           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "sign" ) ) ) {
    1389             : 
    1390           0 :     strncpy( tile->sign.identity_key_path, config->paths.identity_key, sizeof(tile->sign.identity_key_path) );
    1391             : 
    1392           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "plugin" ) ) ) {
    1393             : 
    1394           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "cswtch" ) ) ) {
    1395             : 
    1396           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "gui" ) ) ) {
    1397             : 
    1398           0 :     if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.gui.gui_listen_address, &tile->gui.listen_addr ) ) )
    1399           0 :       FD_LOG_ERR(( "failed to parse gui listen address `%s`", config->tiles.gui.gui_listen_address ));
    1400           0 :     tile->gui.listen_port = config->tiles.gui.gui_listen_port;
    1401           0 :     tile->gui.is_voting = strcmp( config->paths.vote_account, "" );
    1402           0 :     strncpy( tile->gui.cluster, config->cluster, sizeof(tile->gui.cluster) );
    1403           0 :     strncpy( tile->gui.identity_key_path, config->paths.identity_key, sizeof(tile->gui.identity_key_path) );
    1404           0 :     strncpy( tile->gui.vote_key_path, config->paths.vote_account, sizeof(tile->gui.vote_key_path) );
    1405           0 :     tile->gui.max_http_connections      = config->tiles.gui.max_http_connections;
    1406           0 :     tile->gui.max_websocket_connections = config->tiles.gui.max_websocket_connections;
    1407           0 :     tile->gui.max_http_request_length   = config->tiles.gui.max_http_request_length;
    1408           0 :     tile->gui.send_buffer_size_mb       = config->tiles.gui.send_buffer_size_mb;
    1409           0 :     tile->gui.schedule_strategy         = config->tiles.pack.schedule_strategy_enum;
    1410           0 :     tile->gui.websocket_compression     = 1;
    1411           0 :     tile->gui.frontend_release_channel  = config->development.gui.frontend_release_channel_enum;
    1412             : 
    1413           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "rpc" ) ) ) {
    1414             : 
    1415           0 :     if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.rpc.rpc_listen_address, &tile->rpc.listen_addr ) ) )
    1416           0 :       FD_LOG_ERR(( "failed to parse rpc listen address `%s`", config->tiles.rpc.rpc_listen_address ));
    1417           0 :     tile->rpc.listen_port = config->tiles.rpc.rpc_listen_port;
    1418           0 :     tile->rpc.max_http_connections      = config->tiles.rpc.max_http_connections;
    1419           0 :     tile->rpc.max_http_request_length   = config->tiles.rpc.max_http_request_length;
    1420           0 :     tile->rpc.send_buffer_size_mb       = config->tiles.rpc.send_buffer_size_mb;
    1421             : 
    1422           0 :     tile->rpc.max_live_slots = config->firedancer.runtime.max_live_slots;
    1423             : 
    1424           0 :     strncpy( tile->rpc.identity_key_path, config->paths.identity_key, sizeof(tile->rpc.identity_key_path) );
    1425             : 
    1426           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "arch_f" ) ||
    1427           0 :                           !strcmp( tile->name, "arch_w" ) ) ) {
    1428             : 
    1429           0 :     strncpy( tile->archiver.rocksdb_path, config->tiles.archiver.rocksdb_path, sizeof(tile->archiver.rocksdb_path) );
    1430             : 
    1431           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "backt" ) ) ) {
    1432             : 
    1433           0 :     tile->backtest.end_slot = config->tiles.archiver.end_slot;
    1434             : 
    1435             :     /* Validate arguments based on the ingest mode */
    1436           0 :     if( !strcmp( config->tiles.archiver.ingest_mode, "rocksdb" ) ) {
    1437           0 :       strncpy( tile->backtest.rocksdb_path, config->tiles.archiver.rocksdb_path, PATH_MAX );
    1438           0 :       if( FD_UNLIKELY( 0==strlen( tile->backtest.rocksdb_path ) ) ) {
    1439           0 :         FD_LOG_ERR(( "`archiver.rocksdb_path` not specified in toml" ));
    1440           0 :       }
    1441           0 :     } else if( !strcmp( config->tiles.archiver.ingest_mode, "shredcap" ) ) {
    1442           0 :       strncpy( tile->backtest.shredcap_path, config->tiles.archiver.shredcap_path, PATH_MAX );
    1443           0 :       if( FD_UNLIKELY( 0==strlen( tile->backtest.shredcap_path ) ) ) {
    1444           0 :         FD_LOG_ERR(( "`archiver.shredcap_path` not specified in toml" ));
    1445           0 :       }
    1446           0 :     } else {
    1447           0 :       FD_LOG_ERR(( "Invalid ingest mode: %s", config->tiles.archiver.ingest_mode ));
    1448           0 :     }
    1449             : 
    1450           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "scap" ) ) ) {
    1451             : 
    1452           0 :     tile->shredcap.repair_intake_listen_port = config->tiles.repair.repair_intake_listen_port;
    1453           0 :     strncpy( tile->shredcap.folder_path, config->tiles.shredcap.folder_path, sizeof(tile->shredcap.folder_path) );
    1454           0 :     tile->shredcap.write_buffer_size = config->tiles.shredcap.write_buffer_size;
    1455           0 :     tile->shredcap.enable_publish_stake_weights = 0; /* this is not part of the config */
    1456           0 :     strncpy( tile->shredcap.manifest_path, "", PATH_MAX ); /* this is not part of the config */
    1457             : 
    1458           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "bundle" ) ) ) {
    1459           0 :     strncpy( tile->bundle.url, config->tiles.bundle.url, sizeof(tile->bundle.url) );
    1460           0 :     tile->bundle.url_len = strnlen( tile->bundle.url, 255 );
    1461           0 :     strncpy( tile->bundle.sni, config->tiles.bundle.tls_domain_name, 256 );
    1462           0 :     tile->bundle.sni_len = strnlen( tile->bundle.sni, 255 );
    1463           0 :     strncpy( tile->bundle.identity_key_path, config->paths.identity_key, sizeof(tile->bundle.identity_key_path) );
    1464           0 :     strncpy( tile->bundle.key_log_path, config->development.bundle.ssl_key_log_file, sizeof(tile->bundle.key_log_path) );
    1465           0 :     tile->bundle.buf_sz = config->development.bundle.buffer_size_kib<<10;
    1466           0 :     tile->bundle.ssl_heap_sz = config->development.bundle.ssl_heap_size_mib<<20;
    1467           0 :     tile->bundle.keepalive_interval_nanos = config->tiles.bundle.keepalive_interval_millis * (ulong)1e6;
    1468           0 :     tile->bundle.tls_cert_verify = !!config->tiles.bundle.tls_cert_verify;
    1469             : 
    1470           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "vinyl" ) ) ) {
    1471             : 
    1472           0 :     tile->vinyl.vinyl_meta_map_obj_id  = fd_pod_query_ulong( config->topo.props, "vinyl.meta_map",  ULONG_MAX );
    1473           0 :     tile->vinyl.vinyl_meta_pool_obj_id = fd_pod_query_ulong( config->topo.props, "vinyl.meta_pool", ULONG_MAX );
    1474           0 :     tile->vinyl.vinyl_line_max         = config->firedancer.vinyl.max_cache_entries;
    1475           0 :     tile->vinyl.vinyl_cnc_obj_id       = fd_pod_query_ulong( config->topo.props, "vinyl.cnc",       ULONG_MAX );
    1476           0 :     tile->vinyl.vinyl_data_obj_id      = fd_pod_query_ulong( config->topo.props, "vinyl.data",      ULONG_MAX );
    1477           0 :     fd_cstr_ncpy( tile->vinyl.vinyl_bstream_path, config->paths.accounts, sizeof(tile->vinyl.vinyl_bstream_path) );
    1478             : 
    1479           0 :     tile->vinyl.io_type = config->firedancer.vinyl.io_uring.enabled ?
    1480           0 :         FD_VINYL_IO_TYPE_UR : FD_VINYL_IO_TYPE_BD;
    1481           0 :     tile->vinyl.uring_depth = config->firedancer.vinyl.io_uring.queue_depth;
    1482             : 
    1483           0 :   } else {
    1484           0 :     FD_LOG_ERR(( "unknown tile name `%s`", tile->name ));
    1485           0 :   }
    1486           0 : }

Generated by: LCOV version 1.14