LCOV - code coverage report
Current view: top level - app/firedancer - topology.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 1470 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 15 0.0 %

          Line data    Source code
       1             : #include "topology.h"
       2             : #include "../shared/fd_config_json.h"
       3             : 
       4             : #include "../../discof/poh/fd_poh.h"
       5             : #include "../../discof/replay/fd_execrp.h"
       6             : #include "../../discof/genesis/fd_genesi_tile.h"
       7             : #include "../../discof/gossip/fd_gossip_tile.h"
       8             : #include "../../discof/resolv/fd_resolv_tile.h"
       9             : #include "../../discof/repair/fd_repair.h"
      10             : #include "../../discof/replay/fd_replay_tile.h"
      11             : #include "../../discof/replay/fd_sched.h"
      12             : #include "../../discof/votor/fd_votor_tile.h"
      13             : #include "../../disco/keyguard/fd_keyguard.h"
      14             : #include "../../ballet/bls/fd_bls.h"
      15             : #include "../../discof/backup/fd_snapmk_tile.h"
      16             : #include "../../discof/backup/fd_snapsv_tile.h"
      17             : #include "../../disco/shred/fd_shred_tile.h"
      18             : #include "../../disco/store/fd_store.h"
      19             : #include "../../discof/rotor/fd_rotor_tile.h"
      20             : #include "../../choreo/rotor/fd_rotor.h"
      21             : #include "../../disco/net/fd_net_tile.h"
      22             : #include "../../discof/backup/fd_backup.h"
      23             : #include "../../discof/restore/fd_snapct_tile.h"
      24             : #include "../../disco/gui/fd_gui_config_parse.h"
      25             : #include "../../disco/quic/fd_tpu.h"
      26             : #include "../../disco/pack/fd_pack_cost.h"
      27             : #include "../../disco/pack/fd_pack.h"
      28             : #include "../../disco/tiles.h"
      29             : #include "../../disco/topo/fd_topob.h"
      30             : #include "../../disco/topo/fd_cpu_topo.h"
      31             : #include "../../disco/bundle/fd_bundle_tile.h"
      32             : #include "../../tango/dcache/fd_dcache.h"
      33             : #include "../../disco/diag/fd_diag_tile.h"
      34             : #include "../../util/pod/fd_pod_format.h"
      35             : #include "../../discof/restore/utils/fd_ssctrl.h"
      36             : #include "../../discof/restore/utils/fd_ssmsg.h"
      37             : #include "../../flamenco/accdb/fd_accdb_cache.h"
      38             : #include "../../flamenco/capture/fd_solcap_writer.h"
      39             : #include "../../flamenco/progcache/fd_progcache.h"
      40             : #include "../../flamenco/runtime/fd_cost_tracker.h"
      41             : 
      42             : #include <sys/random.h>
      43             : #include <sys/types.h>
      44             : #include <sys/socket.h>
      45             : #include <netdb.h>
      46             : 
      47             : extern fd_topo_obj_callbacks_t * CALLBACKS[];
      48             : extern fd_topo_run_tile_t *      TILES[];
      49             : 
      50             : static ulong
      51           0 : tile_max_event_sz( fd_topo_tile_t const * tile ) {
      52           0 :   for( fd_topo_run_tile_t ** t=TILES; *t; t++ ) {
      53           0 :     if( FD_UNLIKELY( !strcmp( (*t)->name, tile->name ) ) ) {
      54           0 :       return (*t)->max_event_sz ? (*t)->max_event_sz( tile ) : 0UL;
      55           0 :     }
      56           0 :   }
      57           0 :   return 0UL;
      58           0 : }
      59             : 
      60             : void
      61           0 : wire_event_links( fd_topo_t * topo ) {
      62           0 :   fd_topob_wksp( topo, "event_in" );
      63             : 
      64           0 :   ulong tile_cnt = topo->tile_cnt;
      65           0 :   for( ulong i=0UL; i<tile_cnt; i++ ) {
      66           0 :     fd_topo_tile_t * tile = &topo->tiles[ i ];
      67           0 :     if( FD_UNLIKELY( !strcmp( tile->name, "event" ) ) ) continue;
      68             : 
      69           0 :     ulong max_sz = tile_max_event_sz( tile );
      70           0 :     if( FD_LIKELY( !max_sz ) ) continue;
      71             : 
      72           0 :     char link_name[ sizeof(((fd_topo_link_t *)0)->name) ];
      73           0 :     FD_TEST( fd_cstr_printf_check( link_name, sizeof(link_name), NULL, "%s_event", tile->name ) );
      74             : 
      75             :     /* The dcache must cover depth*MTU (a smaller region risks undetected
      76             :        torn reads), so big-MTU links trade depth away to fit the budget. */
      77           0 :     ulong const event_link_dcache_max = 64UL<<20; /* 64 MiB data region per event link */
      78           0 :     ulong depth = 1024UL;
      79           0 :     while( depth>1UL && fd_dcache_req_data_sz( max_sz, depth, 1UL, 1 )>event_link_dcache_max ) depth >>= 1;
      80             : 
      81           0 :     fd_topo_link_t * link = fd_topob_link( topo, link_name, "event_in", depth, max_sz, 1UL );
      82           0 :     link->permit_no_producers = 1; /* written outside fd_stem; topo sees no producer */
      83             : 
      84           0 :     tile->event_link_id = link->id;
      85             : 
      86           0 :     fd_topob_tile_uses( topo, tile, &topo->objs[ link->mcache_obj_id ], FD_SHMEM_JOIN_MODE_READ_WRITE );
      87           0 :     fd_topob_tile_uses( topo, tile, &topo->objs[ link->dcache_obj_id ], FD_SHMEM_JOIN_MODE_READ_WRITE );
      88             : 
      89           0 :     fd_topob_tile_in( topo, "event", 0UL, "metric_in", link_name, link->kind_id, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
      90           0 :   }
      91           0 : }
      92             : 
      93             : fd_topo_obj_t *
      94             : setup_topo_banks( fd_topo_t *  topo,
      95             :                   char const * wksp_name,
      96             :                   ulong        max_live_slots,
      97             :                   ulong        cache_cnt,
      98             :                   ulong        stake_delegation_cache_cnt,
      99           0 :                   ulong        bench_max_cost_per_block ) {
     100           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "banks", wksp_name );
     101           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_live_slots,             "obj.%lu.max_live_slots",             obj->id ) );
     102           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, cache_cnt,                  "obj.%lu.cache_cnt",                  obj->id ) );
     103           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, stake_delegation_cache_cnt, "obj.%lu.stake_delegation_cache_cnt", obj->id ) );
     104           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, bench_max_cost_per_block,   "obj.%lu.bench_max_cost_per_block",   obj->id ) );
     105           0 :   ulong seed;
     106           0 :   FD_TEST( fd_rng_secure( &seed, sizeof( ulong ) ) );
     107           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, seed, "obj.%lu.seed", obj->id ) );
     108           0 :   return obj;
     109           0 : }
     110             : 
     111             : fd_topo_obj_t *
     112             : setup_topo_footer_cache( fd_topo_t *  topo,
     113           0 :                          char const * wksp_name ) {
     114           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "footer_cache", wksp_name );
     115           0 :   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     116           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, obj->id, "footer_cache" ) );
     117           0 :   return obj;
     118           0 : }
     119             : 
     120             : fd_topo_obj_t *
     121             : setup_topo_fec_sets( fd_topo_t *  topo,
     122             :                      char const * wksp_name,
     123           0 :                      ulong        sz ) {
     124           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "fec_sets", wksp_name );
     125           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, sz, "obj.%lu.sz",   obj->id ) );
     126           0 :   return obj;
     127           0 : }
     128             : 
     129             : /* Workspace bytes reserved for the topology's own layout around the cache. */
     130           0 : #define PROGCACHE_WKSP_OVERHEAD_SZ ( 3UL * fd_topo_workspace_align() )
     131             : 
     132             : ulong
     133           0 : setup_topo_progcache_min_sz( ulong txn_max ) {
     134           0 :   ulong min_sz = fd_progcache_shmem_min_sz( txn_max );
     135           0 :   if( FD_UNLIKELY( !min_sz ) ) return 0UL;
     136             :   /* Smallest huge-page multiple holding the cache minimum plus the overhead,
     137             :      so a workspace of exactly this size is what gets locked. */
     138           0 :   return fd_ulong_align_up( min_sz + PROGCACHE_WKSP_OVERHEAD_SZ, FD_SHMEM_HUGE_PAGE_SZ );
     139           0 : }
     140             : 
     141             : void
     142             : setup_topo_progcache( fd_topo_t *  topo,
     143             :                       char const * wksp_name,
     144             :                       ulong        txn_max,
     145           0 :                       ulong        wksp_size ) {
     146           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "progcache", wksp_name );
     147           0 :   FD_TEST( fd_pod_insert_ulong(  topo->props, "progcache", obj->id ) );
     148             : 
     149           0 :   ulong min_wksp_sz = setup_topo_progcache_min_sz( txn_max );
     150           0 :   if( FD_UNLIKELY( !min_wksp_sz ) ) {
     151           0 :     FD_LOG_ERR(( "Invalid [runtime]: max_live_slots is invalid" ));
     152           0 :   }
     153           0 :   if( FD_UNLIKELY( wksp_size<min_wksp_sz ) ) {
     154           0 :     FD_LOG_ERR(( "Invalid [runtime]: program_cache_size_mib must be at least %lu", min_wksp_sz>>20 ));
     155           0 :   }
     156             : 
     157             :   /* The workspace is exactly program_cache_size_mib: the cache gets what is
     158             :      left after the overhead.  For the default 2048 that is 2 gigantic pages. */
     159           0 :   ulong progcache_sz        = wksp_size - PROGCACHE_WKSP_OVERHEAD_SZ;
     160           0 :   ulong progcache_footprint = fd_progcache_shmem_footprint( txn_max, progcache_sz );
     161           0 :   if( FD_UNLIKELY( !progcache_footprint ) ) {
     162           0 :     FD_LOG_ERR(( "Invalid [runtime]: program_cache_size_mib must be at least %lu", min_wksp_sz>>20 ));
     163           0 :   }
     164             : 
     165           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, txn_max, "obj.%lu.txn_max", obj->id ) );
     166           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, progcache_sz, "obj.%lu.progcache_sz", obj->id ) );
     167           0 : }
     168             : 
     169             : fd_topo_obj_t *
     170             : setup_topo_store( fd_topo_t *  topo,
     171             :                   char const * wksp_name,
     172             :                   ulong        fec_max,
     173             :                   ulong        fec_data_max,
     174             :                   ulong        shred_storage_gib,
     175             :                   ulong        shred_cache_mib,
     176             :                   ulong        fec_set_cnt,
     177             :                   ulong        max_shreds_per_block,
     178             :                   char const * db_path,
     179           0 :                   ulong        shred_tile_cnt ) {
     180           0 :   if( FD_UNLIKELY( !shred_cache_mib ) )
     181           0 :     FD_LOG_ERR(( "tiles.shred.shred_cache_size_mib must be non-zero; the FEC payload cache cannot be disabled" ));
     182           0 :   if( FD_UNLIKELY( shred_cache_mib>(ULONG_MAX>>20) ) )
     183           0 :     FD_LOG_ERR(( "tiles.shred.shred_cache_size_mib is too large: %lu", shred_cache_mib ));
     184           0 :   if( FD_UNLIKELY( shred_storage_gib>FD_SHREDB_MAX_SIZE_GIB ) )
     185           0 :     FD_LOG_ERR(( "tiles.rserve.shred_storage_limit_gib is %lu, but the maximum supported size is %lu GiB",
     186           0 :                  shred_storage_gib, FD_SHREDB_MAX_SIZE_GIB ));
     187             : 
     188           0 :   ulong seed;
     189           0 :   FD_TEST( fd_rng_secure( &seed, sizeof( ulong ) ) );
     190             : 
     191           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "store", wksp_name );
     192           0 :   ulong shred_cache_bytes = shred_cache_mib << 20;
     193           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, fec_max,           "obj.%lu.fec_max",           obj->id ) );
     194           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, fec_data_max,      "obj.%lu.fec_data_max",      obj->id ) );
     195           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, shred_storage_gib, "obj.%lu.shred_storage_gib", obj->id ) );
     196           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, shred_cache_bytes, "obj.%lu.shred_cache_bytes", obj->id ) );
     197           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, fec_set_cnt,       "obj.%lu.fec_set_cnt",       obj->id ) );
     198           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_shreds_per_block, "obj.%lu.max_shreds_per_block", obj->id ) );
     199           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, seed,              "obj.%lu.seed",              obj->id ) );
     200           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, shred_tile_cnt,    "obj.%lu.shred_tile_cnt",    obj->id ) );
     201           0 :   if( db_path ) {
     202           0 :     FD_TEST( fd_pod_insertf_cstr( topo->props, db_path,          "obj.%lu.disk_path",         obj->id ) );
     203           0 :   }
     204           0 :   return obj;
     205           0 : }
     206             : 
     207             : fd_topo_obj_t *
     208             : setup_topo_txncache( fd_topo_t *  topo,
     209             :                      char const * wksp_name,
     210             :                      ulong        max_live_slots,
     211           0 :                      ulong        max_txn_per_slot ) {
     212           0 :   ulong seed;
     213           0 :   FD_TEST( fd_rng_secure( &seed, sizeof( ulong ) ) );
     214             : 
     215           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "txncache", wksp_name );
     216           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_live_slots,   "obj.%lu.max_live_slots",   obj->id ) );
     217           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_txn_per_slot, "obj.%lu.max_txn_per_slot", obj->id ) );
     218           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, seed,             "obj.%lu.seed",             obj->id ) );
     219             : 
     220           0 :   return obj;
     221           0 : }
     222             : 
     223             : fd_topo_obj_t *
     224             : setup_topo_accdb( fd_topo_t *  topo,
     225             :                   char const * wksp_name,
     226             :                   ulong        max_accounts,
     227             :                   ulong        max_live_slots,
     228             :                   ulong        max_account_writes_per_slot,
     229             :                   ulong        partition_cnt,
     230             :                   ulong        partition_sz,
     231             :                   ulong        cache_footprint,
     232             :                   int          bundle_enabled,
     233             :                   ulong        joiner_cnt,
     234           0 :                   ulong        max_incremental_accounts ) {
     235           0 :   fd_topo_obj_t * obj = fd_topob_obj( topo, "accdb", wksp_name );
     236             : 
     237           0 :   ulong seed;
     238           0 :   FD_TEST( fd_rng_secure( &seed, sizeof( ulong ) ) );
     239             : 
     240           0 :   ulong cache_min_reserved = fd_accdb_cache_min_reserved( bundle_enabled );
     241             : 
     242           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_accounts,       "obj.%lu.max_accounts",       obj->id ) );
     243           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_live_slots,     "obj.%lu.max_live_slots",     obj->id ) );
     244           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_account_writes_per_slot, "obj.%lu.max_account_writes_per_slot", obj->id ) );
     245           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, partition_cnt,      "obj.%lu.partition_cnt",      obj->id ) );
     246           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, partition_sz,       "obj.%lu.partition_sz",       obj->id ) );
     247           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, cache_footprint,    "obj.%lu.cache_footprint",    obj->id ) );
     248           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, cache_min_reserved, "obj.%lu.cache_min_reserved", obj->id ) );
     249           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, (ulong)!!bundle_enabled, "obj.%lu.bundle_enabled", obj->id ) );
     250           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, joiner_cnt,         "obj.%lu.joiner_cnt",         obj->id ) );
     251           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, max_incremental_accounts, "obj.%lu.max_incremental_accounts", obj->id ) );
     252           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, seed,               "obj.%lu.seed",               obj->id ) );
     253             : 
     254           0 :   return obj;
     255           0 : }
     256             : 
     257             : void
     258           0 : fd_topo_initialize( config_t * config ) {
     259           0 :   ulong net_tile_cnt    = config->layout.net_tile_count;
     260           0 :   ulong shred_tile_cnt  = config->layout.shred_tile_count;
     261           0 :   ulong quic_tile_cnt   = config->layout.quic_tile_count;
     262           0 :   ulong verify_tile_cnt = config->layout.verify_tile_count;
     263           0 :   ulong resolv_tile_cnt = config->firedancer.layout.resolv_tile_count;
     264           0 :   ulong execle_tile_cnt = config->firedancer.layout.execle_tile_count;
     265           0 :   ulong snapzp_tile_cnt = config->firedancer.layout.enable_snapshot_production
     266           0 :                           ? config->firedancer.layout.snapzp_tile_count : 0UL;
     267           0 :   ulong snapsv_tile_cnt = ( config->firedancer.snapshots.server.enabled &&
     268           0 :                             config->firedancer.layout.enable_snapshot_production )
     269           0 :                           ? config->firedancer.layout.snapsv_tile_count : 0UL;
     270           0 :   ulong snapdc_tile_cnt = config->firedancer.layout.snapdc_tile_count;
     271           0 :   ulong snapin_tile_cnt = config->firedancer.layout.snapin_tile_count;
     272             : 
     273           0 :   ulong gossvf_tile_cnt = config->firedancer.layout.gossvf_tile_count;
     274           0 :   ulong execrp_tile_cnt = config->firedancer.layout.execrp_tile_count;
     275           0 :   ulong sign_tile_cnt   = config->firedancer.layout.sign_tile_count;
     276             : 
     277           0 :   ulong genesis_max_message_size = config->firedancer.development.genesis.max_file_size_mib << 20;
     278             : 
     279           0 :   int snapshots_enabled   = !!config->gossip.entrypoints_cnt;
     280           0 :   int snapmk_enabled      = !!snapzp_tile_cnt;
     281           0 :   int rpc_enabled         = config->tiles.rpc.enabled;
     282           0 :   int telemetry_enabled   = config->telemetry && strcmp( config->tiles.event.url, "" );
     283           0 :   int leader_enabled      = !!config->firedancer.layout.enable_block_production;
     284           0 :   int rserve_enabled      = config->tiles.rserve.enabled;
     285           0 :   int efficient_mode      = !strcmp( config->firedancer.layout.mode, "efficient" );
     286           0 :   int gossip_vote_enabled = leader_enabled;
     287             : 
     288           0 :   if( FD_UNLIKELY( snapmk_enabled ) ) {
     289           0 :     FD_CHECK_ERR( config->firedancer.snapshots.max_full_snapshots_to_keep,
     290           0 :                   "[snapshots.max_full_snapshots_to_keep] must be nonzero when [layout.snapzp_tile_count] is nonzero" );
     291           0 :     FD_CHECK_ERR( !config->firedancer.snapshots.incremental_snapshot_interval_blocks ||
     292           0 :                   config->firedancer.snapshots.max_incremental_snapshots_to_keep,
     293           0 :                   "[snapshots.max_incremental_snapshots_to_keep] must be nonzero when incremental snapshot production is enabled" );
     294           0 :   }
     295             : 
     296           0 :   fd_topo_t * topo = fd_topob_new( &config->topo, config->name );
     297             : 
     298           0 :   topo->max_page_size = fd_cstr_to_shmem_page_sz( config->hugetlbfs.max_page_size );
     299           0 :   topo->gigantic_page_threshold = config->hugetlbfs.gigantic_page_threshold_mib << 20;
     300             : 
     301           0 :   int solcap_enabled = strlen( config->capture.solcap_capture ) > 0;
     302             : 
     303             :   /*             topo, name */
     304           0 :   fd_topob_wksp( topo, "metric" );
     305           0 :   fd_topob_wksp( topo, "diag"   );
     306           0 :   fd_topob_wksp( topo, "genesi" );
     307           0 :   fd_topob_wksp( topo, "ipecho" );
     308           0 :   fd_topob_wksp( topo, "gossvf" );
     309           0 :   fd_topob_wksp( topo, "gossip" );
     310           0 :   fd_topob_wksp( topo, "shred"  );
     311           0 :   fd_topob_wksp( topo, "rotor"  );
     312           0 :   if( rserve_enabled ) fd_topob_wksp( topo, "rserve" );
     313           0 :   fd_topob_wksp( topo, "replay" );
     314           0 :   fd_topob_wksp( topo, "accdb"  );
     315           0 :   fd_topob_wksp( topo, "execrp" );
     316           0 :   fd_topob_wksp( topo, "votor" );
     317           0 :   fd_topob_wksp( topo, "sign"   )->core_dump_level = FD_TOPO_CORE_DUMP_LEVEL_NEVER;
     318           0 :   fd_topob_wksp( topo, "admin"  )->core_dump_level = FD_TOPO_CORE_DUMP_LEVEL_NEVER;
     319             : 
     320           0 :   if( leader_enabled ) {
     321           0 :     fd_topob_wksp( topo, "quic"   );
     322           0 :     fd_topob_wksp( topo, "verify" );
     323           0 :     fd_topob_wksp( topo, "dedup"  );
     324           0 :     fd_topob_wksp( topo, "resolv" );
     325           0 :     fd_topob_wksp( topo, "pack"   );
     326           0 :     fd_topob_wksp( topo, "execle" );
     327           0 :     fd_topob_wksp( topo, "motor"  );
     328           0 :   } else {
     329           0 :     execle_tile_cnt = 0UL;
     330           0 :     resolv_tile_cnt = 0UL;
     331           0 :     quic_tile_cnt   = 0UL;
     332           0 :     verify_tile_cnt = 0UL;
     333           0 :     config->tiles.bundle.enabled = 0;
     334           0 :   }
     335           0 :   fd_topob_wksp( topo, "metric_in"    );
     336           0 :   if( FD_LIKELY( config->tiles.gui.enabled ) ) fd_topob_wksp( topo, "diag_gui" );
     337           0 :   if( FD_LIKELY( config->tiles.gui.enabled ) ) fd_topob_wksp( topo, "gossip_gui" );
     338             : 
     339           0 :   fd_topob_wksp( topo, "net_gossip"   );
     340           0 :   fd_topob_wksp( topo, "net_shred"    );
     341           0 :   fd_topob_wksp( topo, "net_repair"   );
     342           0 :   if( rserve_enabled ) fd_topob_wksp( topo, "net_rserve" );
     343           0 :   fd_topob_wksp( topo, "net_votor" );
     344           0 :   if( leader_enabled ) fd_topob_wksp( topo, "net_quic" );
     345             : 
     346           0 :   fd_topob_wksp( topo, "genesi_out"    );
     347           0 :   fd_topob_wksp( topo, "ipecho_out"    );
     348           0 :   fd_topob_wksp( topo, "gossvf_gossip" );
     349           0 :   fd_topob_wksp( topo, "gossip_gossvf" );
     350           0 :   fd_topob_wksp( topo, "gossip_ciaddr" );
     351           0 :   if( FD_LIKELY( config->tiles.gui.enabled ) ) fd_topob_wksp( topo, "gossip_ciseen" );
     352           0 :   if( gossip_vote_enabled ) fd_topob_wksp( topo, "gossip_vote" );
     353           0 :   fd_topob_wksp( topo, "gossip_misc"   );
     354             : 
     355           0 :   fd_topob_wksp( topo, "shred_out"     );
     356           0 :   fd_topob_wksp( topo, "repair_out" );
     357           0 :   fd_topob_wksp( topo, "replay_epoch"  );
     358           0 :   fd_topob_wksp( topo, "replay_execrp" );
     359           0 :   fd_topob_wksp( topo, "replay_out"    );
     360           0 :   fd_topob_wksp( topo, "replay_slot"   );
     361           0 :   fd_topob_wksp( topo, "votor_out" );
     362             : 
     363           0 :   if( leader_enabled ) {
     364           0 :     fd_topob_wksp( topo, "quic_verify"   );
     365           0 :     fd_topob_wksp( topo, "verify_dedup"  );
     366           0 :     fd_topob_wksp( topo, "dedup_resolv"  );
     367           0 :     fd_topob_wksp( topo, "resolv_pack"   );
     368           0 :     fd_topob_wksp( topo, "pack_poh"      );
     369           0 :     fd_topob_wksp( topo, "pack_execle"   );
     370           0 :     fd_topob_wksp( topo, "resolv_replay" );
     371           0 :     if( FD_LIKELY( config->tiles.pack.use_consumed_cus ) ) {
     372           0 :       fd_topob_wksp( topo, "execle_pack" );
     373           0 :     }
     374           0 :     fd_topob_wksp( topo, "execle_poh"    );
     375           0 :     fd_topob_wksp( topo, "execle_busy"   );
     376           0 :     fd_topob_wksp( topo, "poh_shred"     );
     377           0 :     fd_topob_wksp( topo, "poh_replay"    );
     378           0 :   }
     379             : 
     380           0 :   fd_topob_wksp( topo, "adminctl"      )->core_dump_level = FD_TOPO_CORE_DUMP_LEVEL_NEVER;
     381             : 
     382           0 :   fd_topob_wksp( topo, "progcache"     );
     383           0 :   fd_topob_wksp( topo, "txncache"      );
     384           0 :   fd_topob_wksp( topo, "accdb_data"    )->core_dump_level = FD_TOPO_CORE_DUMP_LEVEL_FULL;
     385           0 :   fd_topob_wksp( topo, "banks"         );
     386           0 :   fd_topob_wksp( topo, "store"         )->core_dump_level = FD_TOPO_CORE_DUMP_LEVEL_FULL;
     387           0 :   fd_topob_wksp( topo, "rnonce"        );
     388             : 
     389           0 :   fd_topob_wksp( topo, "gossip_sign"   );
     390           0 :   fd_topob_wksp( topo, "sign_gossip"   );
     391             : 
     392           0 :   fd_topob_wksp( topo, "shred_sign"    );
     393           0 :   fd_topob_wksp( topo, "sign_shred"    );
     394             : 
     395           0 :   fd_topob_wksp( topo, "repair_sign"   );
     396           0 :   fd_topob_wksp( topo, "sign_repair"   );
     397             : 
     398           0 :   if( rserve_enabled ) {
     399           0 :     fd_topob_wksp( topo, "rserve_sign"   );
     400           0 :     fd_topob_wksp( topo, "sign_rserve"   );
     401           0 :     fd_topob_wksp( topo, "rotor_rserve" );
     402           0 :   }
     403             : 
     404           0 :   fd_topob_wksp( topo, "votor_sign"  );
     405           0 :   fd_topob_wksp( topo, "sign_votor"  );
     406             : 
     407           0 :   fd_topob_wksp( topo, "execrp_replay" );
     408           0 :   fd_topob_wksp( topo, "admin_replay"  );
     409             : 
     410           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
     411           0 :     fd_topob_wksp( topo, "snapct"      );
     412           0 :     fd_topob_wksp( topo, "snapld"      );
     413           0 :     fd_topob_wksp( topo, "snapdc"      );
     414           0 :     fd_topob_wksp( topo, "snapin"      );
     415           0 :     fd_topob_wksp( topo, "snapct_ld"   );
     416           0 :     fd_topob_wksp( topo, "snapld_dc"   );
     417           0 :     fd_topob_wksp( topo, "snapdc_in"   );
     418           0 :     fd_topob_wksp( topo, "snapin_ct"   );
     419           0 :     fd_topob_wksp( topo, "snapin_shmem" );
     420             : 
     421           0 :     if( FD_LIKELY( config->tiles.gui.enabled ) ) fd_topob_wksp( topo, "snapct_gui"  );
     422           0 :     if( FD_LIKELY( config->tiles.gui.enabled ) ) fd_topob_wksp( topo, "snapin_gui"  );
     423           0 :     fd_topob_wksp( topo, "snapin_manif" );
     424           0 :     fd_topob_wksp( topo, "snapct_repr"  );
     425           0 :   }
     426           0 :   if( snapmk_enabled ) {
     427           0 :     fd_topob_wksp( topo, "snapmk"        );
     428           0 :     fd_topob_wksp( topo, "snapzp"        );
     429           0 :     fd_topob_wksp( topo, "snapmk_zp"     );
     430           0 :     fd_topob_wksp( topo, "replay_snapmk" );
     431           0 :     fd_topob_wksp( topo, "snapmk_out"    );
     432           0 :     fd_topob_wksp( topo, "snaprd"        );
     433           0 :     fd_topob_wksp( topo, "snaprd_out"    );
     434           0 :     if( snapsv_tile_cnt ) {
     435           0 :       fd_topob_wksp( topo, "snapsv"     );
     436           0 :       fd_topob_wksp( topo, "snapsv_out" );
     437           0 :     }
     438           0 :   }
     439             : 
     440           0 :   #define FOR(cnt) for( ulong i=0UL; i<cnt; i++ )
     441             : 
     442           0 :   ulong shred_depth = 65536UL;
     443             : 
     444             :   /* Under Alpenglow, rotor redelivers every FEC set replay can hold when
     445             :      replay loses a parent bank, and polls nothing until that is
     446             :      published, so repair_out holds all of it. */
     447             : 
     448           0 :   ulong repair_out_depth = fd_ulong_pow2_up( config->firedancer.runtime.max_live_slots * (config->limits.max_shreds_per_block/FD_FEC_SHRED_CNT) );
     449             : 
     450             :   /*                                  topo, link_name,       wksp_name,       depth,                                    mtu,                           burst */
     451           0 :   /**/                 fd_topob_link( topo, "gossip_net",    "net_gossip",    32768UL,                                  FD_NET_MTU,                    1UL );
     452           0 :   FOR(shred_tile_cnt)  fd_topob_link( topo, "shred_net",     "net_shred",     32768UL,                                  FD_NET_MTU,                    1UL );
     453           0 :   /**/                 fd_topob_link( topo, "repair_net",    "net_repair",    config->net.ingress_buffer_size,          FD_NET_MTU,                    1UL );
     454           0 :   FOR(quic_tile_cnt)   fd_topob_link( topo, "quic_net",      "net_quic",      config->net.ingress_buffer_size,          FD_NET_MTU,                    1UL );
     455             : 
     456           0 :   if( FD_LIKELY( rserve_enabled ) ) {
     457           0 :     /**/               fd_topob_link( topo, "rserve_net",    "net_rserve",    config->net.ingress_buffer_size,          FD_NET_MTU,                    1UL );
     458           0 :     /**/               fd_topob_link( topo, "rserve_sign",   "rserve_sign",   128UL,                                    32UL,                          1UL );
     459           0 :     /**/               fd_topob_link( topo, "sign_rserve",   "sign_rserve",   128UL,                                    sizeof(fd_ed25519_sig_t),      1UL );
     460           0 :     /**/               fd_topob_link( topo, "rotor_rserve",  "rotor_rserve",  2048UL,                                   sizeof(fd_rotor_block_t),      1UL );
     461           0 :   }
     462             : 
     463           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
     464             :     /* TODO: Revisit the depths of all the snapshot links */
     465           0 :     /**/                 fd_topob_link( topo, "snapct_ld",     "snapct_ld",     128UL,                                    sizeof(fd_ssctrl_msg_t),       1UL );
     466           0 :     /**/                 fd_topob_link( topo, "snapld_dc",     "snapld_dc",     FD_SNAPSHOT_DATA_DEPTH,                   FD_SNAPSHOT_DATA_MTU,          1UL );
     467           0 :     FOR(snapdc_tile_cnt) fd_topob_link( topo, "snapdc_in",     "snapdc_in",     FD_SNAPSHOT_DC_IN_DEPTH,                  FD_SNAPSHOT_DATA_MTU,          1UL );
     468             : 
     469             :     /**/                 fd_topob_link( topo, "snapin_manif",  "snapin_manif",  4UL,                                      sizeof(fd_snapshot_manifest_t),1UL ); /* only 3 frags ever traverse: FULL, INCREMENTAL, DONE */
     470           0 :     /**/                 fd_topob_link( topo, "snapct_repr",   "snapct_repr",   128UL,                                    0UL,                           1UL )->permit_no_consumers = 1; /* TODO: wire in repair later */
     471           0 :     if( FD_LIKELY( config->tiles.gui.enabled ) ) {
     472           0 :       /**/               fd_topob_link( topo, "snapct_gui",    "snapct_gui",    128UL,                                    sizeof(fd_snapct_update_t),    1UL );
     473           0 :       FOR(snapin_tile_cnt) fd_topob_link( topo, "snapin_gui",    "snapin_gui",    128UL,                                    FD_GUI_CONFIG_PARSE_MAX_VALID_ACCT_SZ, 1UL );
     474           0 :     }
     475           0 :     FOR(snapin_tile_cnt) fd_topob_link( topo, "snapin_ct",     "snapin_ct",     128UL,                                    0UL,                           1UL );
     476           0 :   }
     477           0 :   FOR(snapzp_tile_cnt) fd_topob_link( topo, "snapmk_zp",     "snapmk_zp",     1024UL,                                   sizeof(fd_backup_frag_t),      1UL );
     478           0 :   if( snapmk_enabled ) fd_topob_link( topo, "replay_snapmk", "replay_snapmk", 16UL,                                     sizeof(fd_replay_snap_start_t),1UL );
     479           0 :   if( snapmk_enabled ) fd_topob_link( topo, "snapmk_out",    "snapmk_out",    128UL,                                    sizeof(fd_snapmk_msg_t),       1UL );
     480           0 :   if( snapmk_enabled ) fd_topob_link( topo, "snaprd_out",    "snaprd_out",    1024UL,                                   FD_BACKUP_RD_MTU,              1UL );
     481           0 :   FOR(snapsv_tile_cnt) fd_topob_link( topo, "snapsv_out",    "snapsv_out",    16384UL,                                  sizeof(fd_snapsv_msg_t),       1UL )->permit_no_consumers = 1;
     482           0 :   fd_topo_obj_t * zp_fseq = NULL;
     483           0 :   if( snapmk_enabled ) {
     484           0 :     zp_fseq = fd_topob_obj( topo, "fseq", "snapmk" );
     485           0 :     FD_TEST( fd_pod_insert_ulong( topo->props, "snapzp.fseq", zp_fseq->id ) );
     486             : 
     487           0 :     fd_topo_obj_t * backup = fd_topob_obj( topo, "backup", "snapmk" );
     488           0 :     FD_TEST( fd_pod_insertf_ulong( topo->props, config->firedancer.accounts.max_accounts, "obj.%lu.max_accounts", backup->id ) );
     489           0 :     FD_TEST( fd_pod_insert_ulong( topo->props, "backup", backup->id ) );
     490           0 :   }
     491             : 
     492           0 :   /**/                 fd_topob_link( topo, "genesi_out",    "genesi_out",    1UL,                                      fd_genesi_tile_mtu( genesis_max_message_size ), 1UL );
     493           0 :   /**/                 fd_topob_link( topo, "ipecho_out",    "ipecho_out",    2UL,                                      0UL,                           1UL );
     494           0 :   FOR(gossvf_tile_cnt) fd_topob_link( topo, "gossvf_gossip", "gossvf_gossip", config->net.ingress_buffer_size,          FD_GOSSIP_GOSSVF_MTU,          1UL );
     495           0 :   /**/                 fd_topob_link( topo, "gossip_gossvf", "gossip_gossvf", 65536UL*4UL,                              sizeof(fd_gossip_ping_update_t), 1UL ); /* TODO: Unclear where this depth comes from ... fix */
     496           0 :   /**/                 fd_topob_link( topo, "gossip_ciaddr", "gossip_ciaddr", 65536UL*2UL,                              sizeof(fd_gossip_update_message_t), 1UL ); /* min pow2 >= gossip's STEM_BURST */
     497           0 :   if( FD_LIKELY( config->tiles.gui.enabled ) ) {
     498           0 :                        fd_topob_link( topo, "gossip_ciseen", "gossip_ciseen", 65536UL*2UL,                              sizeof(fd_gossip_update_message_t), 1UL );
     499           0 :   }
     500           0 :   if( gossip_vote_enabled ) {
     501           0 :                        fd_topob_link( topo, "gossip_vote",   "gossip_vote",   65536UL*4UL,                              sizeof(fd_gossip_update_message_t), 1UL );
     502           0 :   }
     503           0 :   /**/                 fd_topob_link( topo, "gossip_misc",   "gossip_misc",   65536UL*2UL,                              sizeof(fd_gossip_update_message_t), 1UL );
     504             : 
     505           0 :   FOR(quic_tile_cnt)   fd_topob_link( topo, "quic_verify",   "quic_verify",   config->tiles.verify.receive_buffer_size, sizeof(fd_tpu_msg_t),          config->tiles.quic.txn_reassembly_count );
     506           0 :   FOR(verify_tile_cnt) fd_topob_link( topo, "verify_dedup",  "verify_dedup",  1024UL,                                   FD_TPU_PARSED_MTU,             1UL ); /* shallow enough to stay in cache */
     507           0 :   /**/                 fd_topob_link( topo, "replay_epoch",  "replay_epoch",  32UL,                                     FD_EPOCH_OUT_MTU,              1UL ); /* replay publishes two epochs at boot and must keep STEM_BURST (4) credits after */
     508           0 :   /**/                 fd_topob_link( topo, "replay_out",    "replay_out",    65536UL,                                  sizeof(fd_replay_message_t),   1UL )->permit_no_consumers = 1;
     509           0 :   /**/                 fd_topob_link( topo, "replay_slot",   "replay_slot",   4096UL,                                   sizeof(fd_replay_message_t),   1UL );
     510           0 :   /**/                 fd_topob_link( topo, "replay_rotor",  "replay_slot",   16UL,                                     sizeof(fd_replay_message_t),   1UL ); /* REPLAY_SIG_MISSING_FEC; >= replay's STEM_BURST (4) */
     511           0 :   FOR(execrp_tile_cnt) fd_topob_link( topo, "replay_execrp", "replay_execrp", 256UL,                                    sizeof(fd_execrp_task_msg_t),  1UL );
     512           0 :   /**/                 fd_topob_link( topo, "admin_replay",  "admin_replay",  32UL,                                     0UL,                           1UL );
     513           0 :   /**/                 fd_topob_link( topo, "replay_admin",  "admin_replay",  32UL,                                     0UL,                           1UL );
     514           0 :   if( leader_enabled ) {
     515           0 :     /**/                   fd_topob_link( topo, "dedup_resolv",  "dedup_resolv",  16384UL,                                  FD_TPU_PARSED_MTU,             1UL );
     516           0 :     FOR(resolv_tile_cnt)   fd_topob_link( topo, "resolv_pack",   "resolv_pack",   4096UL,                                   FD_TPU_RESOLVED_MTU,           1UL );
     517           0 :     /**/                   fd_topob_link( topo, "pack_poh",      "pack_poh",      4096UL,                                   sizeof(fd_done_packing_t),     1UL );
     518           0 :     FOR(execle_tile_cnt)   fd_topob_link( topo, "execle_poh",    "execle_poh",    4096UL,                                   FD_EXECLE_POH_MTU,             1UL );
     519           0 :     FOR(execle_tile_cnt)   fd_topob_link( topo, "pack_execle",   "pack_execle",   128UL,                                     FD_PACK_EXECLE_MTU,           1UL ); /* execle returns credits per frag, so this can be shallow enough for pack to keep in cache */
     520           0 :     if( FD_LIKELY( config->tiles.pack.use_consumed_cus ) ) {
     521           0 :       FOR(execle_tile_cnt) fd_topob_link( topo, "execle_pack",   "execle_pack",   1024UL,                                   FD_PACK_REBATE_MAX_SZ,         1UL );
     522           0 :     }
     523           0 :     /**/                   fd_topob_link( topo, "poh_shred",     "poh_shred",     4096UL,                                   FD_POH_SHRED_MTU,              1UL );
     524           0 :     /**/                   fd_topob_link( topo, "poh_replay",    "poh_replay",    4096UL,                                   sizeof(fd_poh_leader_slot_ended_t), 1UL );
     525           0 :   }
     526             : 
     527           0 :   FOR(resolv_tile_cnt) fd_topob_link( topo, "resolv_replay", "resolv_replay", 4096UL,                                   sizeof(fd_resolv_slot_exchanged_t), 1UL );
     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",   256UL,                                    FD_REPAIR_MAX_PREIMAGE_SZ,     1UL ); /* See repair_tile.c for explanation */
     536           0 :   FOR(sign_tile_cnt-1) fd_topob_link( topo, "sign_repair",   "sign_repair",   256UL,                                    sizeof(fd_ed25519_sig_t),      1UL );
     537             : 
     538           0 :   FOR(shred_tile_cnt)  fd_topob_link( topo, "shred_out",     "shred_out",     shred_depth,                              sizeof(fd_shred_message_t),    FD_SHRED_STEM_BURST );
     539           0 :   /**/                 fd_topob_link( topo, "repair_out",    "repair_out",    repair_out_depth,                         sizeof(fd_rotor_replay_fec_t), 1UL );
     540             : 
     541           0 :   FOR(execrp_tile_cnt) fd_topob_link( topo, "execrp_replay", "execrp_replay", 16384UL,                                  sizeof(fd_execrp_task_done_msg_t), 1UL );
     542           0 :   if( FD_LIKELY( config->tiles.gui.enabled ) ) {
     543           0 :     fd_topob_link( topo, "diag_gui", "diag_gui", 4UL, sizeof(fd_diag_system_resources_t), 1UL );
     544           0 :     /**/                 fd_topob_link( topo, "gossip_gui",  "gossip_gui",    256UL,                                    FD_GUI_GOSSIP_BW_MTU,          1UL );
     545           0 :     FOR(gossvf_tile_cnt) fd_topob_link( topo, "gossvf_gui",  "gossip_gui",    256UL,                                    FD_GUI_GOSSIP_BW_MTU,          1UL );
     546           0 :   }
     547             : 
     548           0 :   ushort parsed_tile_to_cpu[ FD_TILE_MAX ];
     549             :   /* Unassigned tiles will be floating, unless auto topology is enabled. */
     550           0 :   for( ulong i=0UL; i<FD_TILE_MAX; i++ ) parsed_tile_to_cpu[ i ] = USHORT_MAX;
     551             : 
     552           0 :   int is_auto_affinity = !strcmp( config->layout.affinity, "auto" );
     553             : 
     554           0 :   fd_topo_cpus_t cpus[1];
     555           0 :   fd_topo_cpus_init( cpus );
     556             : 
     557           0 :   ulong affinity_tile_cnt = 0UL;
     558           0 :   if( FD_LIKELY( !is_auto_affinity ) ) affinity_tile_cnt = fd_topob_parse_affinity_cstr( config->layout.affinity, parsed_tile_to_cpu, 1, 1 );
     559             : 
     560           0 :   ulong tile_to_cpu[ FD_TILE_MAX ];
     561           0 :   for( ulong i=0UL; i<FD_TILE_MAX; i++ ) tile_to_cpu[ i ] = ULONG_MAX;
     562             : 
     563           0 :   for( ulong i=0UL; i<affinity_tile_cnt; i++ ) {
     564           0 :     ushort cpu_idx = (ushort)( parsed_tile_to_cpu[ i ] & ~FD_TOPOB_CPU_SHARED );
     565           0 :     if( FD_UNLIKELY( parsed_tile_to_cpu[ i ]!=USHORT_MAX && cpu_idx>=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 :                    cpu_idx, 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 :   if( FD_UNLIKELY( efficient_mode ) ) fd_topob_sleep( topo, "metric_in", tile_to_cpu[ topo->tile_cnt ] );
     574             : 
     575           0 :   int xsk_core_dump = config->development.core_dump_level >= FD_TOPO_CORE_DUMP_LEVEL_REGULAR ? 1 : 0;
     576           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, xsk_core_dump, tile_to_cpu );
     577             : 
     578           0 :   FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_gossvf", i, config->net.ingress_buffer_size );
     579           0 :   FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_shred",  i, config->net.ingress_buffer_size );
     580           0 :   FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_repair", i, config->net.ingress_buffer_size );
     581           0 :   if( rserve_enabled ) FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_rserve", i, config->net.ingress_buffer_size );
     582           0 :   if( leader_enabled ) FOR(net_tile_cnt) fd_topos_net_rx_link( topo, "net_quic",   i, config->net.ingress_buffer_size );
     583             : 
     584             :   /*                                  topo, tile_name, tile_wksp, metrics_wksp, cpu_idx,                       uses_id_keyswitch, uses_av_keyswitch, is_waker_client */
     585             :   /**/                 fd_topob_tile( topo, "metric",  "metric",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,                 0,                 1 );
     586           0 :   /**/                 fd_topob_tile( topo, "diag",    "diag",    "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,                 0,                 0 );
     587           0 :   if( FD_LIKELY( config->tiles.gui.enabled ) )
     588           0 :     fd_topob_tile_out( topo, "diag", 0UL, "diag_gui", 0UL );
     589             : 
     590           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
     591           0 :     /**/                 fd_topob_tile( topo, "snapct", "snapct", "metric_in", tile_to_cpu[ topo->tile_cnt ],    0,                 0,                 1 )->allow_shutdown = 1;
     592           0 :     /**/                 fd_topob_tile( topo, "snapld", "snapld", "metric_in", tile_to_cpu[ topo->tile_cnt ],    0,                 0,                 1 )->allow_shutdown = 1;
     593           0 :     FOR(snapdc_tile_cnt) fd_topob_tile( topo, "snapdc", "snapdc", "metric_in", tile_to_cpu[ topo->tile_cnt ],    0,                 0,                 0 )->allow_shutdown = 1;
     594           0 :     FOR(snapin_tile_cnt) fd_topob_tile( topo, "snapin", "snapin", "metric_in", tile_to_cpu[ topo->tile_cnt ],    0,                 0,                 0 )->allow_shutdown = 1;
     595           0 :   }
     596           0 :   if( snapmk_enabled ) {
     597           0 :     /**/                 fd_topob_tile( topo, "snapmk", "snapmk", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0, 0 );
     598           0 :     FOR(snapzp_tile_cnt) fd_topob_tile( topo, "snapzp", "snapzp", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0, 0 );
     599           0 :     /**/                 fd_topob_tile( topo, "snaprd", "snaprd", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0, 0 );
     600           0 :     FOR(snapsv_tile_cnt) fd_topob_tile( topo, "snapsv", "snapsv", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0, 0 );
     601           0 :   }
     602             : 
     603             :   /**/                 fd_topob_tile( topo, "genesi",  "genesi",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,                 0,                 1 )->allow_shutdown = 1;
     604           0 :   /**/                 fd_topob_tile( topo, "ipecho",  "ipecho",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,                 0,                 1 );
     605           0 :   FOR(gossvf_tile_cnt) fd_topob_tile( topo, "gossvf",  "gossvf",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 1,                 0,                 0 );
     606           0 :   /**/                 fd_topob_tile( topo, "gossip",  "gossip",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 1,                 0,                 0 );
     607             : 
     608           0 :   FOR(shred_tile_cnt)  fd_topob_tile( topo, "shred",   "shred",   "metric_in",  tile_to_cpu[ topo->tile_cnt ], 1,                 0,                 0 );
     609           0 :   /**/                 fd_topob_tile( topo, "rotor",   "rotor",   "metric_in",  tile_to_cpu[ topo->tile_cnt ], 1,                 0,                 0 );
     610           0 :   if( rserve_enabled) {
     611           0 :     /**/               fd_topob_tile( topo, "rserve",  "rserve",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 1,                 0,                 0 );
     612           0 :   }
     613           0 :   /**/                 fd_topob_tile( topo, "replay",  "replay",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 1,                 0,                 0 );
     614           0 :   /**/                 fd_topob_tile( topo, "accdb",   "accdb",   "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,                 0,                 0 );
     615           0 :   FOR(execrp_tile_cnt) fd_topob_tile( topo, "execrp",  "execrp",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,                 0,                 0 );
     616           0 :   /**/                 fd_topob_tile( topo, "votor",   "votor",   "metric_in",  tile_to_cpu[ topo->tile_cnt ], 1,                 1,                 0 );
     617             : 
     618           0 :   if( leader_enabled ) {
     619           0 :     FOR(quic_tile_cnt)   fd_topob_tile( topo, "quic",    "quic",    "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,               0,               0 );
     620           0 :     FOR(verify_tile_cnt) fd_topob_tile( topo, "verify",  "verify",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,               0,               0 );
     621           0 :     /**/                 fd_topob_tile( topo, "dedup",   "dedup",   "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,               0,               0 );
     622           0 :     FOR(resolv_tile_cnt) fd_topob_tile( topo, "resolv",  "resolv",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,               0,               0 );
     623           0 :     /**/                 fd_topob_tile( topo, "pack",    "pack",    "metric_in",  tile_to_cpu[ topo->tile_cnt ], config->tiles.bundle.enabled, 0, 0 );
     624           0 :     FOR(execle_tile_cnt) fd_topob_tile( topo, "execle",  "execle",  "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,               0,               0 );
     625           0 :     /**/                 fd_topob_tile( topo, "motor",   "motor",   "metric_in",  tile_to_cpu[ topo->tile_cnt ], 0,               0,               0 );
     626           0 :   }
     627           0 :   FOR(sign_tile_cnt)   fd_topob_tile( topo, "sign",    "sign",    "metric_in",  tile_to_cpu[ topo->tile_cnt ], 1,               1,               0 );
     628             : 
     629           0 :   if( FD_UNLIKELY( rpc_enabled ) ) {
     630           0 :     fd_topob_wksp( topo, "rpc" );
     631           0 :     fd_topob_wksp( topo, "rpc_replay" );
     632           0 :     fd_topob_tile( topo, "rpc", "rpc", "metric_in", tile_to_cpu[ topo->tile_cnt ], 1, 0, 1 );
     633           0 :   }
     634             : 
     635           0 :   if( FD_UNLIKELY( solcap_enabled ) ) {
     636           0 :     fd_topob_wksp( topo, "solcap" );
     637           0 :     fd_topob_tile( topo, "solcap", "solcap", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0, 0 );
     638           0 :   }
     639             : 
     640           0 :   fd_topo_tile_t * admin_tile = fd_topob_tile( topo, "admin", "admin", "metric_in", tile_to_cpu[ topo->tile_cnt ], 0, 0, 0 );
     641             : 
     642             :   /*                                        topo, tile_name, tile_kind_id, fseq_wksp,   link_name,       link_kind_id, reliable,            polled */
     643           0 :   FOR(gossvf_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
     644           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 */
     645           0 :   FOR(shred_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
     646           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 */
     647           0 :   FOR(net_tile_cnt)   fd_topob_tile_in(     topo, "rotor",   0UL,          "metric_in", "net_repair",    i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
     648           0 :   /**/                fd_topob_tile_out(    topo, "rotor",   0UL,                       "repair_net",    0UL                                                );
     649           0 :   FOR(quic_tile_cnt) for( ulong j=0UL; j<net_tile_cnt; j++ )
     650           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 */
     651           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 */
     652           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 */
     653           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 */
     654           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 */
     655             : 
     656           0 :   /**/                 fd_topob_tile_out(   topo, "genesi", 0UL,                        "genesi_out",    0UL                                                );
     657           0 :   /**/                 fd_topob_tile_in (   topo, "ipecho", 0UL,           "metric_in", "genesi_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     658           0 :   /**/                 fd_topob_tile_out(   topo, "ipecho", 0UL,                        "ipecho_out",    0UL                                                );
     659             : 
     660           0 :   FOR(gossvf_tile_cnt) fd_topob_tile_out(   topo, "gossvf", i,                          "gossvf_gossip", i                                                  );
     661           0 :   FOR(gossvf_tile_cnt) fd_topob_tile_in (   topo, "gossvf", i,             "metric_in", "gossip_ciaddr", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     662           0 :   FOR(gossvf_tile_cnt) fd_topob_tile_in (   topo, "gossvf", i,             "metric_in", "gossip_gossvf", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     663           0 :   FOR(gossvf_tile_cnt) fd_topob_tile_in (   topo, "gossvf", i,             "metric_in", "ipecho_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     664           0 :   FOR(gossvf_tile_cnt) fd_topob_tile_in (   topo, "gossvf", i,             "metric_in", "replay_epoch",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     665           0 :   /**/                 fd_topob_tile_in (   topo, "gossip", 0UL,           "metric_in", "replay_epoch",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     666           0 :   /**/                 fd_topob_tile_out(   topo, "gossip", 0UL,                        "gossip_ciaddr", 0UL                                                );
     667           0 :   if( FD_LIKELY( config->tiles.gui.enabled ) ) {
     668           0 :                        fd_topob_tile_out(   topo, "gossip", 0UL,                        "gossip_ciseen", 0UL                                                );
     669           0 :   }
     670           0 :   if( gossip_vote_enabled ) {
     671           0 :                        fd_topob_tile_out(   topo, "gossip", 0UL,                        "gossip_vote",   0UL                                                );
     672           0 :   }
     673           0 :   /**/                 fd_topob_tile_out(   topo, "gossip", 0UL,                        "gossip_misc",   0UL                                                );
     674           0 :   /**/                 fd_topob_tile_out(   topo, "gossip", 0UL,                        "gossip_net",    0UL                                                );
     675           0 :   /**/                 fd_topob_tile_in (   topo, "gossip", 0UL,           "metric_in", "ipecho_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     676           0 :   FOR(gossvf_tile_cnt) fd_topob_tile_in (   topo, "gossip", 0UL,           "metric_in", "gossvf_gossip", i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
     677           0 :   /**/                 fd_topob_tile_out(   topo, "gossip", 0UL,                        "gossip_gossvf", 0UL                                                );
     678           0 :   if( rserve_enabled ) {
     679           0 :     FOR(net_tile_cnt) fd_topob_tile_in(     topo, "rserve",  0UL,          "metric_in", "net_rserve",    i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
     680           0 :     FOR(shred_tile_cnt) fd_topob_tile_in(   topo, "rserve",  0UL,          "metric_in", "shred_out",     i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     681           0 :     /**/              fd_topob_tile_out(    topo, "rserve",  0UL,                       "rserve_net",    0UL                                                );
     682           0 :     /**/              fd_topos_tile_in_net( topo,                          "metric_in", "rserve_net",    0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED ); /* No reliable consumers of networking fragments, may be dropped or overrun */
     683           0 :     /**/              fd_topob_tile_out(    topo, "rotor",   0UL,                       "rotor_rserve",  0UL                                                );
     684           0 :     /**/              fd_topob_tile_in(     topo, "rserve",  0UL,          "metric_in", "rotor_rserve",  0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
     685           0 :   }
     686           0 :   if( snapshots_enabled ) {
     687           0 :                        fd_topob_tile_in (   topo, "gossip",  0UL,          "metric_in", "snapin_manif",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     688           0 :   }
     689           0 :   int snapshots_gossip_enabled = config->firedancer.snapshots.sources.gossip.allow_any || config->firedancer.snapshots.sources.gossip.allow_list_cnt>0UL;
     690           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
     691           0 :     if( FD_LIKELY( snapshots_gossip_enabled ) ) {
     692           0 :       /**/            fd_topob_tile_in (    topo, "snapct",  0UL,          "metric_in", "gossip_ciaddr", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     693           0 :     }
     694             : 
     695           0 :                       fd_topob_tile_in (    topo, "snapct",  0UL,          "metric_in", "snapld_dc",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     696           0 :                       fd_topob_tile_out(    topo, "snapct",  0UL,                       "snapct_ld",     0UL                                                );
     697           0 :                       fd_topob_tile_out(    topo, "snapct",  0UL,                       "snapct_repr",   0UL                                                );
     698           0 :     if( FD_LIKELY( config->tiles.gui.enabled ) ) {
     699           0 :       /**/            fd_topob_tile_out(    topo, "snapct",  0UL,                       "snapct_gui",    0UL                                                );
     700           0 :     }
     701             : 
     702             : 
     703           0 :     FOR(snapin_tile_cnt) fd_topob_tile_out(    topo, "snapin",  i,                       "snapin_ct",    i                                                   );
     704           0 :     FOR(snapin_tile_cnt) fd_topob_tile_in (    topo, "snapct",  0UL,          "metric_in", "snapin_ct",    i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     705           0 :     /**/              fd_topob_tile_in (    topo, "snapld",  0UL,          "metric_in", "snapct_ld",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     706           0 :     /**/              fd_topob_tile_out(    topo, "snapld",  0UL,                       "snapld_dc",     0UL                                                );
     707             : 
     708           0 :     FOR(snapdc_tile_cnt) fd_topob_tile_in (    topo, "snapdc",  i,            "metric_in", "snapld_dc",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     709           0 :     FOR(snapdc_tile_cnt) fd_topob_tile_out(    topo, "snapdc",  i,                      "snapdc_in",     i                                                  );
     710             : 
     711           0 :     for( ulong t=0UL; t<snapin_tile_cnt; t++ ) {
     712           0 :       FOR(snapdc_tile_cnt) fd_topob_tile_in( topo, "snapin", t, "metric_in", "snapdc_in", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     713           0 :     }
     714           0 :     if( FD_LIKELY( config->tiles.gui.enabled ) ) {
     715           0 :       FOR(snapin_tile_cnt) fd_topob_tile_out(    topo, "snapin", i,                          "snapin_gui",    i                                                  );
     716           0 :     }
     717           0 :                       fd_topob_tile_out(    topo, "snapin",  0UL,                       "snapin_manif",  0UL                                                );
     718           0 :   }
     719             : 
     720           0 :   /**/                 fd_topob_tile_in(    topo, "rotor",   0UL,          "metric_in", "genesi_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     721           0 :   /**/                 fd_topob_tile_in(    topo, "rotor",   0UL,          "metric_in", "gossip_ciaddr", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     722           0 :   /**/                 fd_topob_tile_in(    topo, "rotor",   0UL,          "metric_in", "replay_epoch",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     723           0 :   /**/                 fd_topob_tile_in(    topo, "rotor",   0UL,          "metric_in", "replay_slot",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     724           0 :   /**/                 fd_topob_tile_in(    topo, "rotor",   0UL,          "metric_in", "replay_rotor",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     725           0 :   FOR(shred_tile_cnt)  fd_topob_tile_in(    topo, "rotor",   0UL,          "metric_in", "shred_out",     i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     726           0 :   if( snapshots_enabled ) {
     727           0 :                        fd_topob_tile_in(    topo, "rotor",   0UL,          "metric_in", "snapin_manif",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     728           0 :   }
     729           0 :   /**/                 fd_topob_tile_out(   topo, "rotor",   0UL,                       "repair_out",    0                                                  );
     730             : 
     731           0 :   /**/                 fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "repair_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     732           0 :   /**/                 fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "genesi_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     733           0 :   /**/                 fd_topob_tile_out(   topo, "replay",  0UL,                       "replay_out",    0UL                                                );
     734           0 :   /**/                 fd_topob_tile_out(   topo, "replay",  0UL,                       "replay_slot",   0UL                                                );
     735           0 :   /**/                 fd_topob_tile_out(   topo, "replay",  0UL,                       "replay_rotor",  0UL                                                );
     736           0 :   /**/                 fd_topob_tile_out(   topo, "replay",  0UL,                       "replay_epoch",  0UL                                                );
     737           0 :   FOR(execrp_tile_cnt) fd_topob_tile_out(   topo, "replay",  0UL,                       "replay_execrp", i                                                  );
     738           0 :   FOR(execrp_tile_cnt) fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "execrp_replay", i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     739           0 :   if(leader_enabled)  {fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "poh_replay",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );}
     740           0 :   FOR(resolv_tile_cnt) fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "resolv_replay", i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     741           0 :   /**/                 fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "ipecho_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     742           0 :   /**/                 fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "gossip_misc",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     743           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
     744           0 :                        fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "snapin_manif",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     745           0 :   }
     746           0 :   if( snapmk_enabled ) {
     747           0 :     /*               */fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "snapmk_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     748           0 :   }
     749           0 :   FOR(snapsv_tile_cnt) fd_topob_tile_in (   topo, "snapsv",  i,            "metric_in", "snapmk_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     750           0 :   FOR(snapsv_tile_cnt) fd_topob_tile_out(   topo, "snapsv",  i,                         "snapsv_out",    i                                                  );
     751           0 :   /**/                 fd_topob_tile_in (   topo, "replay",  0UL,          "metric_in", "admin_replay",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     752           0 :   /**/                 fd_topob_tile_out(   topo, "replay",  0UL,                       "replay_admin",  0UL                                                );
     753           0 :   /**/                 fd_topob_tile_out(   topo, "admin",   0UL,                       "admin_replay",  0UL                                                );
     754           0 :   /**/                 fd_topob_tile_in (   topo, "admin",   0UL,          "metric_in", "replay_admin",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     755             : 
     756           0 :   FOR(execrp_tile_cnt) fd_topob_tile_in (   topo, "execrp",  i,            "metric_in", "replay_execrp", i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     757           0 :   FOR(execrp_tile_cnt) fd_topob_tile_out(   topo, "execrp",  i,                         "execrp_replay", i                                                  );
     758             : 
     759           0 :   if( leader_enabled ) {
     760           0 :     FOR(quic_tile_cnt)   fd_topob_tile_out( topo, "quic",    i,                         "quic_verify",   i                                                  );
     761           0 :     FOR(quic_tile_cnt)   fd_topob_tile_out( topo, "quic",    i,                         "quic_net",      i                                                  );
     762             :     /* All verify tiles read from all QUIC tiles, packets are round robin. */
     763           0 :     FOR(verify_tile_cnt) for( ulong j=0UL; j<quic_tile_cnt; j++ )
     764           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 */
     765           0 :     FOR(verify_tile_cnt) fd_topob_tile_in(  topo, "verify",  i,            "metric_in", "gossip_vote",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     766           0 :     FOR(verify_tile_cnt) fd_topob_tile_out( topo, "verify",  i,                         "verify_dedup",  i                                                  );
     767           0 :     FOR(verify_tile_cnt) fd_topob_tile_in(  topo, "dedup",   0UL,          "metric_in", "verify_dedup",  i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     768           0 :     /**/                 fd_topob_tile_in(  topo, "dedup",   0UL,          "metric_in", "replay_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     769           0 :     /**/                 fd_topob_tile_out( topo, "dedup",   0UL,                       "dedup_resolv",  0UL                                                );
     770           0 :     FOR(resolv_tile_cnt) fd_topob_tile_in(  topo, "resolv",  i,            "metric_in", "dedup_resolv",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     771           0 :     FOR(resolv_tile_cnt) fd_topob_tile_in(  topo, "resolv",  i,            "metric_in", "replay_slot",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     772           0 :     FOR(resolv_tile_cnt) fd_topob_tile_out( topo, "resolv",  i,                         "resolv_pack",   i                                                  );
     773           0 :     FOR(resolv_tile_cnt) fd_topob_tile_out( topo, "resolv",  i,                         "resolv_replay", i                                                  );
     774           0 :     FOR(resolv_tile_cnt) fd_topob_tile_in(  topo, "pack",    0UL,          "metric_in", "resolv_pack",   i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     775           0 :     /**/                 fd_topob_tile_in(  topo, "pack",    0UL,          "metric_in", "replay_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     776           0 :     FOR(execle_tile_cnt) fd_topob_tile_out(  topo, "pack",   0UL,                       "pack_execle",   i                                                  );
     777           0 :     /**/                 fd_topob_tile_out(  topo, "pack",   0UL,                       "pack_poh" ,     0UL                                                );
     778           0 :     if( FD_LIKELY( config->tiles.pack.use_consumed_cus ) ) {
     779           0 :       FOR(execle_tile_cnt) fd_topob_tile_in(  topo, "pack",  0UL,          "metric_in", "execle_pack",   i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     780           0 :     }
     781           0 :     FOR(execle_tile_cnt) fd_topob_tile_in ( topo, "execle",  i,            "metric_in", "pack_execle",   i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     782           0 :     FOR(execle_tile_cnt) fd_topob_tile_out( topo, "execle",  i,                         "execle_poh",    i                                                  );
     783           0 :     if( FD_LIKELY( config->tiles.pack.use_consumed_cus ) ) {
     784           0 :       FOR(execle_tile_cnt)fd_topob_tile_out(topo, "execle",  i,                         "execle_pack",   i                                                  );
     785           0 :     }
     786           0 :     FOR(execle_tile_cnt) fd_topob_tile_in ( topo, "motor",   0UL,          "metric_in", "execle_poh",    i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     787           0 :     /**/                 fd_topob_tile_in ( topo, "motor",   0UL,          "metric_in", "pack_poh",      0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     788           0 :     /**/                 fd_topob_tile_in ( topo, "motor",   0UL,          "metric_in", "replay_slot",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     789           0 :     /**/                 fd_topob_tile_out( topo, "motor",   0UL,                       "poh_shred",     0UL                                                );
     790           0 :     /**/                 fd_topob_tile_out( topo, "motor",   0UL,                       "poh_replay",    0UL                                                );
     791           0 :     FOR(shred_tile_cnt)  fd_topob_tile_in ( topo, "shred",   i,            "metric_in", "poh_shred",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     792           0 :   }
     793             : 
     794           0 :   FOR(shred_tile_cnt)    fd_topob_tile_in ( topo, "shred",   i,            "metric_in", "replay_epoch",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     795           0 :   FOR(shred_tile_cnt)    fd_topob_tile_in ( topo, "shred",   i,            "metric_in", "gossip_ciaddr", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     796           0 :   FOR(shred_tile_cnt)    fd_topob_tile_out( topo, "shred",   i,                         "shred_out",     i                                                  );
     797           0 :   FOR(shred_tile_cnt)    fd_topob_tile_in ( topo, "shred",   i,            "metric_in", "ipecho_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
     798           0 :   FOR(shred_tile_cnt)    fd_topob_tile_in ( topo, "shred",   i,            "metric_in", "replay_slot",   0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
     799           0 :   FOR(shred_tile_cnt)    fd_topob_tile_out( topo, "shred",   i,                         "shred_net",     i                                                  );
     800             : 
     801           0 :   if( FD_LIKELY( telemetry_enabled ) ) {
     802           0 :     fd_topob_wksp( topo, "event"      );
     803           0 :     fd_topob_wksp( topo, "event_sign" );
     804           0 :     fd_topob_wksp( topo, "sign_event" );
     805           0 :     fd_topob_link( topo, "event_sign", "event_sign", 128UL, 317UL, 1UL );
     806           0 :     fd_topob_link( topo, "sign_event", "sign_event", 128UL, 64UL, 1UL );
     807           0 :     fd_topob_tile( topo, "event", "event", "metric_in",  tile_to_cpu[ topo->tile_cnt ], 1, 0, 1 );
     808           0 :     fd_topob_tile_in(  topo, "event",  0UL, "metric_in", "genesi_out", 0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
     809           0 :     fd_topob_tile_in(  topo, "event",  0UL, "metric_in", "ipecho_out", 0UL, FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
     810             : 
     811           0 :     if( FD_UNLIKELY( config->development.event.report_shreds ) ) {
     812             :       /* TODO: This needs to be reliable, else we could miss shreds that
     813             :          are required to replay the chain, but we can't change it yet as
     814             :          the XDP tile does not support reliable consumers. */
     815           0 :       FOR(net_tile_cnt) fd_topob_tile_in(  topo, "event", 0UL, "metric_in", "net_shred", i, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
     816           0 :     }
     817             : 
     818           0 :     if( FD_UNLIKELY( config->development.event.report_transactions && leader_enabled ) ) {
     819           0 :       fd_topob_tile_in( topo, "event", 0UL, "metric_in", "dedup_resolv", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     820           0 :     }
     821             : 
     822           0 :     fd_topob_tile_in(  topo, "sign",   0UL, "metric_in", "event_sign", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     823           0 :     fd_topob_tile_out( topo, "event",  0UL,              "event_sign", 0UL                                         );
     824           0 :     fd_topob_tile_in(  topo, "event",  0UL, "metric_in", "sign_event", 0UL, FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
     825           0 :     fd_topob_tile_out( topo, "sign",   0UL,              "sign_event", 0UL                                         );
     826           0 :   }
     827             : 
     828           0 :   if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
     829           0 :     fd_topob_wksp( topo, "bundle_verif" );
     830           0 :     fd_topob_wksp( topo, "bundle_sign"  );
     831           0 :     fd_topob_wksp( topo, "sign_bundle"  );
     832           0 :     fd_topob_wksp( topo, "pack_sign"    );
     833           0 :     fd_topob_wksp( topo, "sign_pack"    );
     834           0 :     fd_topob_wksp( topo, "bundle"       );
     835             : 
     836           0 :     /**/                 fd_topob_link( topo, "bundle_verif", "bundle_verif", config->tiles.verify.receive_buffer_size, FD_TPU_PARSED_MTU,         1UL );
     837           0 :     /**/                 fd_topob_link( topo, "bundle_sign",  "bundle_sign",  65536UL,                                  9UL,                       1UL );
     838           0 :     /**/                 fd_topob_link( topo, "sign_bundle",  "sign_bundle",  128UL,                                    64UL,                      1UL );
     839           0 :     /**/                 fd_topob_link( topo, "pack_sign",    "pack_sign",    65536UL,                                  1232UL,                    1UL );
     840           0 :     /**/                 fd_topob_link( topo, "sign_pack",    "sign_pack",    128UL,                                    64UL,                      1UL );
     841             : 
     842             :     /**/                 fd_topob_tile( topo, "bundle",  "bundle",  "metric_in", tile_to_cpu[ topo->tile_cnt ], 1, 0, 1 );
     843             : 
     844             :     /**/                 fd_topob_tile_out( topo, "bundle", 0UL, "bundle_verif", 0UL );
     845           0 :     FOR(verify_tile_cnt) fd_topob_tile_in(  topo, "verify", i,             "metric_in", "bundle_verif",   0UL,        FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
     846             : 
     847           0 :     /**/                 fd_topob_tile_in(  topo, "sign",   0UL,           "metric_in", "bundle_sign",    0UL,        FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     848           0 :     /**/                 fd_topob_tile_out( topo, "bundle", 0UL,                        "bundle_sign",    0UL                                                );
     849           0 :     /**/                 fd_topob_tile_in(  topo, "bundle", 0UL,           "metric_in", "sign_bundle",    0UL,        FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
     850           0 :     /**/                 fd_topob_tile_out( topo, "sign",   0UL,                        "sign_bundle",    0UL                                                );
     851             : 
     852           0 :     if( leader_enabled ) {
     853           0 :       /**/               fd_topob_tile_in(  topo, "sign",   0UL,           "metric_in", "pack_sign",      0UL,        FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     854           0 :       /**/               fd_topob_tile_out( topo, "pack",   0UL,                        "pack_sign",      0UL                                                );
     855           0 :       /**/               fd_topob_tile_in(  topo, "pack",   0UL,           "metric_in", "sign_pack",      0UL,        FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
     856           0 :       /**/               fd_topob_tile_out( topo, "sign",   0UL,                        "sign_pack",      0UL                                                );
     857           0 :     }
     858             : 
     859           0 :     if( leader_enabled ) fd_topob_tile_in(  topo, "bundle", 0UL,           "metric_in", "replay_slot",    0UL,        FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     860             : 
     861           0 :     if( config->tiles.gui.enabled ) { /* GUI is the only consumer of bundle_status */
     862           0 :       fd_topob_wksp( topo, "bundle_status" );
     863             :       /* bundle_status must be kind of deep, to prevent exhausting
     864             :          shared flow control credits when publishing many packets at
     865             :          once. */
     866           0 :       fd_topob_link( topo, "bundle_status", "bundle_status", 128UL, sizeof(fd_bundle_block_engine_update_t), 1UL );
     867           0 :       fd_topob_tile_out( topo, "bundle", 0UL, "bundle_status", 0UL );
     868           0 :     }
     869           0 :   }
     870             : 
     871             :   /* Sign links don't need to be reliable because each requester has a
     872             :      small bounded number of requests in flight: one for the tiles that
     873             :      sign synchronously and read the response out of band in a spin
     874             :      loop (their response link is not polled by fd_stem), and up to
     875             :      FD_SHRED_SIGN_PEND_MAX for shred, which takes its responses as
     876             :      ordinary polled frags.
     877             : 
     878             :      TODO: This can probably be fixed now to be reliable ... ? */
     879             :   /*                                        topo, tile_name, tile_kind_id, fseq_wksp,   link_name,      link_kind_id, reliable,            polled */
     880           0 :   /**/                 fd_topob_tile_in (   topo, "sign",    0UL,          "metric_in", "gossip_sign",  0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     881           0 :   /**/                 fd_topob_tile_out(   topo, "gossip",  0UL,                       "gossip_sign",  0UL                                                  );
     882           0 :   /**/                 fd_topob_tile_in (   topo, "gossip",  0UL,          "metric_in", "sign_gossip",  0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     883           0 :   /**/                 fd_topob_tile_out(   topo, "sign",    0UL,                       "sign_gossip",  0UL                                                  );
     884             : 
     885           0 :   for( ulong i=0UL; i<shred_tile_cnt; i++ ) {
     886           0 :     /**/               fd_topob_tile_in (   topo, "sign",    0UL,          "metric_in", "shred_sign",   i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     887           0 :     /**/               fd_topob_tile_out(   topo, "shred",   i,                         "shred_sign",   i                                                    );
     888           0 :     /**/               fd_topob_tile_in (   topo, "shred",   i,            "metric_in", "sign_shred",   i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     889           0 :     /**/               fd_topob_tile_out(   topo, "sign",    0UL,                       "sign_shred",   i                                                    );
     890           0 :   }
     891             : 
     892           0 :   FOR(sign_tile_cnt-1UL) fd_topob_tile_out( topo, "rotor",   0UL,                       "repair_sign",  i                                                    );
     893           0 :   FOR(sign_tile_cnt-1UL) fd_topob_tile_in ( topo, "sign",    i+1UL,        "metric_in", "repair_sign",  i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
     894           0 :   FOR(sign_tile_cnt-1UL) fd_topob_tile_out( topo, "sign",    i+1UL,                     "sign_repair",  i                                                    );
     895           0 :   FOR(sign_tile_cnt-1UL) fd_topob_tile_in ( topo, "rotor",   0UL,          "metric_in", "sign_repair",  i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   ); /* This link is polled because the signing requests are asynchronous */
     896             : 
     897           0 :   if( rserve_enabled ) {
     898           0 :     /**/                 fd_topob_tile_in (   topo, "sign",    0UL,          "metric_in", "rserve_sign",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
     899           0 :     /**/                 fd_topob_tile_out(   topo, "rserve",  0UL,                       "rserve_sign",  0UL                                                  );
     900           0 :     /**/                 fd_topob_tile_in (   topo, "rserve",  0UL,          "metric_in", "sign_rserve",  0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
     901           0 :     /**/                 fd_topob_tile_out(   topo, "sign",    0UL,                       "sign_rserve",  0UL                                                  );
     902           0 :   }
     903             : 
     904           0 :   if( FD_UNLIKELY( rpc_enabled ) ) {
     905           0 :     fd_topob_link( topo, "rpc_replay", "rpc_replay", 8UL, 0UL, 1UL );
     906           0 :     fd_topob_tile_out( topo, "rpc", 0UL, "rpc_replay", 0UL );
     907             : 
     908           0 :     fd_topob_tile_in( topo, "rpc",    0UL, "metric_in", "replay_slot",  0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     909           0 :     fd_topob_tile_in( topo, "rpc",    0UL, "metric_in", "genesi_out",   0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     910           0 :     fd_topob_tile_in( topo, "replay", 0UL, "metric_in", "rpc_replay",   0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     911           0 :     fd_topob_tile_in( topo, "rpc",    0UL, "metric_in", "gossip_ciaddr", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     912           0 :     fd_topob_tile_in( topo, "rpc",    0UL, "metric_in", "replay_epoch", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     913           0 :   }
     914             : 
     915           0 :   if( FD_UNLIKELY( solcap_enabled ) ) {
     916           0 :     fd_topob_link( topo, "cap_repl", "solcap", 32UL, SOLCAP_WRITE_ACCOUNT_DATA_MTU, 1UL );
     917           0 :     fd_topob_tile_out( topo, "replay", 0UL, "cap_repl", 0UL );
     918           0 :     fd_topob_tile_in( topo, "solcap", 0UL, "metric_in", "cap_repl", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     919           0 :     FOR(execrp_tile_cnt) fd_topob_link( topo, "cap_execrp", "solcap", 32UL, SOLCAP_WRITE_ACCOUNT_DATA_MTU, 1UL );
     920           0 :     FOR(execrp_tile_cnt) fd_topob_tile_out( topo, "execrp", i, "cap_execrp", i );
     921           0 :     FOR(execrp_tile_cnt) fd_topob_tile_in( topo, "solcap", 0UL, "metric_in", "cap_execrp", i, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     922           0 :   }
     923             : 
     924           0 :   if( snapmk_enabled ) {
     925           0 :     /**/                 fd_topob_tile_out( topo, "replay", 0UL,              "replay_snapmk", 0UL                                     );
     926           0 :     /**/                 fd_topob_tile_in ( topo, "snapmk", 0UL, "metric_in", "replay_snapmk", 0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     927           0 :     /**/                 fd_topob_tile_in ( topo, "snapmk", 0UL, "metric_in", "snaprd_out",    0UL, FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     928           0 :     FOR(snapzp_tile_cnt) fd_topob_tile_out( topo, "snapmk", 0UL,              "snapmk_zp",     i                                       );
     929           0 :     FOR(snapzp_tile_cnt) fd_topob_tile_in ( topo, "snapzp", i,   "metric_in", "snapmk_zp",     i,   FD_TOPOB_RELIABLE, FD_TOPOB_POLLED );
     930           0 :     /**/                 fd_topob_tile_out( topo, "snapmk", 0UL,              "snapmk_out",    0UL                                     );
     931           0 :     /**/                 fd_topob_tile_out( topo, "snaprd", 0UL,              "snaprd_out",    0UL                                     );
     932           0 :   }
     933             : 
     934           0 :   fd_topo_obj_t * admin_ctl = fd_topob_obj_named( topo, "adminctl", "adminctl", "admin" );
     935           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, admin_ctl->id, "adminctl" ) );
     936           0 :   fd_topob_tile_uses( topo, admin_tile, admin_ctl, FD_SHMEM_JOIN_MODE_READ_WRITE );
     937             : 
     938             :   /* There is a special fseq that sits between the pack, execle, and poh
     939             :      tiles to indicate when the execle/poh tiles are done processing a
     940             :      microblock.  Pack uses this to determine when to "unlock" accounts
     941             :      that it marked as locked because they were being used. */
     942             : 
     943           0 :   for( ulong i=0UL; i<execle_tile_cnt; i++ ) {
     944           0 :     fd_topo_obj_t * busy_obj = fd_topob_obj( topo, "fseq", "execle_busy" );
     945             : 
     946           0 :     fd_topo_tile_t * pack_tile = &topo->tiles[ fd_topo_find_tile( topo, "pack", 0UL ) ];
     947           0 :     fd_topo_tile_t * execle_tile = &topo->tiles[ fd_topo_find_tile( topo, "execle", i ) ];
     948           0 :     fd_topob_tile_uses( topo, pack_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
     949           0 :     fd_topob_tile_uses( topo, execle_tile, busy_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     950           0 :     FD_TEST( fd_pod_insertf_ulong( topo->props, busy_obj->id, "execle_busy.%lu", i ) );
     951           0 :   }
     952             : 
     953             :   /* Repair and shred share a secret they use to generate the nonces.
     954             :      It's not super security sensitive, but for good hygiene, we make it
     955             :      an object. */
     956           0 :   if( 1 /* just restrict the scope for these variables in this big function */ ) {
     957           0 :     fd_topo_obj_t * rnonce_ss_obj = fd_topob_obj( topo, "rnonce_ss", "rnonce" );
     958           0 :     fd_topo_tile_t * repair_tile = &topo->tiles[ fd_topo_find_tile( topo, "rotor", 0UL ) ];
     959           0 :     fd_topob_tile_uses( topo, repair_tile, rnonce_ss_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     960           0 :     for( ulong i=0UL; i<shred_tile_cnt; i++ ) {
     961           0 :       fd_topo_tile_t * shred_tile = &topo->tiles[ fd_topo_find_tile( topo, "shred", i ) ];
     962           0 :       fd_topob_tile_uses( topo, shred_tile, rnonce_ss_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
     963           0 :     }
     964           0 :     FD_TEST( fd_pod_insertf_ulong( topo->props, rnonce_ss_obj->id, "rnonce_ss" ) );
     965           0 :   }
     966             : 
     967             :   /* node_info holds various rarely-changing config that cannot be
     968             :      represented as simple scalar metrics */
     969           0 :   fd_topo_obj_t * node_info_obj = fd_topob_obj( topo, "node_info", "replay" );
     970           0 :   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], node_info_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     971           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, node_info_obj->id, "node_info" ) );
     972             : 
     973             :   /* wait_info holds data for the wait command's safe-restart-window checks */
     974           0 :   fd_topo_obj_t * wait_info_obj = fd_topob_obj( topo, "wait_info", "replay" );
     975           0 :   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], wait_info_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     976           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, wait_info_obj->id, "wait_info" ) );
     977             : 
     978           0 :   if( leader_enabled ) {
     979           0 :     fd_topo_obj_t * ldr_tt_obj = fd_topob_obj( topo, "ldr_tt", "motor" );
     980           0 :     FD_TEST( fd_pod_insertf_ulong( topo->props, config->limits.max_txn_per_slot, "obj.%lu.max_txn_per_slot", ldr_tt_obj->id ) );
     981           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "motor",  0UL ) ], ldr_tt_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     982           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], ldr_tt_obj, FD_SHMEM_JOIN_MODE_READ_ONLY  );
     983           0 :     FD_TEST( fd_pod_insertf_ulong( topo->props, ldr_tt_obj->id, "ldr_tt" ) );
     984           0 :   }
     985             : 
     986           0 :   ulong min_bank_cache_cnt = fd_ulong_min( execrp_tile_cnt, FD_SCHED_MAX_STAGING_LANES )+2UL;
     987           0 :   if( FD_UNLIKELY( config->firedancer.runtime.bank_cache_cnt<min_bank_cache_cnt ) ) {
     988           0 :     FD_LOG_ERR(( "Invalid [runtime]: bank_cache_cnt is %lu, but it must be at least %lu (2 more than the smaller of [layout] "
     989           0 :                  "execrp_tile_count %lu and %lu replay staging lanes).  Increase [runtime] bank_cache_cnt.",
     990           0 :                  config->firedancer.runtime.bank_cache_cnt, min_bank_cache_cnt, execrp_tile_cnt, FD_SCHED_MAX_STAGING_LANES ));
     991           0 :   }
     992           0 :   fd_topo_obj_t * banks_obj = setup_topo_banks( topo, "banks", config->firedancer.runtime.max_live_slots, config->firedancer.runtime.bank_cache_cnt, config->firedancer.runtime.stake_delegation_cache_cnt, config->development.bench.max_cost_per_block );
     993           0 :   /**/                 fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     994           0 :   FOR(execrp_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "execrp", i   ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     995           0 :   setup_topo_footer_cache( topo, "banks" );
     996           0 :   FOR(execle_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "execle", i   ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
     997           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  );
     998           0 :   if( snapmk_enabled ) {
     999           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapmk", 0UL ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1000           0 :   }
    1001           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
    1002           0 :     FOR(snapin_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapin", i ) ], banks_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1003           0 :   }
    1004           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, banks_obj->id, "banks" ) );
    1005             : 
    1006           0 :   if( FD_UNLIKELY( config->firedancer.runtime.max_live_slots<32UL ) ) FD_LOG_ERR(( "max_live_slots must be >= 32" ));
    1007             : 
    1008           0 :   setup_topo_progcache( topo, "progcache",
    1009           0 :       config->firedancer.runtime.max_live_slots,
    1010           0 :       config->firedancer.runtime.program_cache_size_mib<<20 );
    1011           0 :   ulong progcache_obj_id; FD_TEST( (progcache_obj_id = fd_pod_query_ulong( topo->props, "progcache", ULONG_MAX ))!=ULONG_MAX );
    1012           0 :   fd_topo_obj_t * progcache_obj = &topo->objs[ progcache_obj_id ];
    1013             : 
    1014           0 :   /**/                 fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], progcache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1015           0 :   /**/                 fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "accdb",  0UL ) ], progcache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1016           0 :   FOR(execrp_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "execrp", i   ) ], progcache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1017           0 :   FOR(execle_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "execle", i   ) ], progcache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1018             : 
    1019           0 :   if( FD_LIKELY( config->tiles.gui.enabled ) ) {
    1020           0 :     fd_topob_wksp( topo, "gui"        );
    1021             : 
    1022             :     /**/                 fd_topob_tile(     topo, "gui",     "gui",     "metric_in",  tile_to_cpu[ topo->tile_cnt ], 1, 0, 1 );
    1023             : 
    1024             :     /**/                   fd_topob_tile_out( topo, "gossip", 0UL,                        "gossip_gui",    0UL                                                );
    1025           0 :     FOR(gossvf_tile_cnt)   fd_topob_tile_out( topo, "gossvf", i,                          "gossvf_gui",    i                                                  );
    1026             : 
    1027             :     /*                                        topo, tile_name, tile_kind_id, fseq_wksp,   link_name,       link_kind_id, reliable,            polled */
    1028           0 :     FOR(gossvf_tile_cnt)   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "gossvf_gui",    i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
    1029           0 :     /**/                   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "repair_net",    0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
    1030           0 :     FOR(shred_tile_cnt)    fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "shred_out",     i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1031           0 :     /**/                   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "gossip_gui",    0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
    1032           0 :     /**/                   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "gossip_ciseen", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1033           0 :     /**/                   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "replay_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1034           0 :     /**/                   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "replay_epoch",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1035           0 :     /**/                   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "genesi_out",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1036           0 :     /**/                   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "diag_gui",      0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
    1037           0 :     if( leader_enabled ) {
    1038           0 :       /**/                 fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "pack_poh",      0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1039           0 :       FOR(execle_tile_cnt) fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "pack_execle",   i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1040           0 :       FOR(execle_tile_cnt) fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "execle_poh",    i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1041           0 :     }
    1042           0 :     FOR(execrp_tile_cnt)   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "execrp_replay", i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1043             : 
    1044           0 :     if( FD_LIKELY( snapshots_enabled ) ) {
    1045           0 :     /**/                   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "snapct_gui",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1046           0 :     FOR(snapin_tile_cnt)   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "snapin_gui",    i,            FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1047           0 :     /**/                   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "snapin_manif",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1048           0 :     }
    1049           0 :     FOR(snapsv_tile_cnt)   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "snapsv_out",    i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED );
    1050           0 :     if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
    1051           0 :     /**/                   fd_topob_tile_in(  topo, "gui",    0UL,           "metric_in", "bundle_status", 0UL,         FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED );
    1052           0 :     }
    1053           0 :   }
    1054             : 
    1055           0 :   if( FD_LIKELY( !is_auto_affinity ) ) {
    1056           0 :     if( FD_UNLIKELY( affinity_tile_cnt<topo->tile_cnt ) )
    1057           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. "
    1058           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 "
    1059           0 :                    "the total tile count. You can reduce the tile count by decreasing individual tile counts in the [layout] section of the configuration file.",
    1060           0 :                    topo->tile_cnt, affinity_tile_cnt ));
    1061           0 :     if( FD_UNLIKELY( affinity_tile_cnt>topo->tile_cnt ) )
    1062           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. "
    1063           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 "
    1064           0 :                        "individual tile counts in the [layout] section of the configuration file.",
    1065           0 :                        topo->tile_cnt, affinity_tile_cnt ));
    1066           0 :   } else {
    1067           0 :     ushort blocklist_cores[ FD_TILE_MAX ];
    1068           0 :     topo->blocklist_cores_cnt = fd_topob_parse_affinity_cstr( config->layout.blocklist_cores, blocklist_cores, 0, 0 );
    1069           0 :     if( FD_UNLIKELY( topo->blocklist_cores_cnt>FD_TILE_MAX ) ) {
    1070           0 :       FD_LOG_ERR(( "The CPU string in the configuration file under [layout.blocklist_cores] specifies more CPUs than Firedancer can use. "
    1071           0 :                     "You should reduce the number of CPUs in the excluded cores string." ));
    1072           0 :     }
    1073             : 
    1074           0 :     for( ulong i=0UL; i<topo->blocklist_cores_cnt; i++ ) {
    1075             :       /* Since we use fd_topob_parse_affinity_cstr() like for affinity, the user
    1076             :          may input a string containing `f`. That's parsed correctly, but it's
    1077             :          meaningless for blocklisted cores, so we reject it here.  */
    1078           0 :       if( FD_UNLIKELY( blocklist_cores[ i ]==USHORT_MAX ) ) {
    1079           0 :         FD_LOG_ERR(( "The CPU string in the configuration file under [layout.blocklist_cores] contains invalid values: `f`. "
    1080           0 :                       "You should fix the excluded cores string." ));
    1081           0 :       }
    1082           0 :       topo->blocklist_cores_cpu_idx[ i ] = blocklist_cores[ i ];
    1083           0 :     }
    1084           0 :   }
    1085             : 
    1086             :   /* Alpenglow links and tile connections.  The optional GUI tile has
    1087             :      been created by this point. */
    1088           0 :   /**/               fd_topob_link( topo, "votor_out",     "votor_out",     8192UL,                                   sizeof(fd_votor_msg_t),                        FD_VOTOR_OUT_BURST );
    1089           0 :   /**/               fd_topob_link( topo, "votor_net",     "net_votor",     32768UL,                                  FD_NET_MTU,                                    FD_VOTOR_NET_BURST ); /* as shred_net: fan-out publishes as it goes and rides depth, burst covers only the deferred aio flush */
    1090           0 :   /**/               fd_topob_link( topo, "votor_sign",    "votor_sign",    128UL,                                    FD_KEYGUARD_SIGN_REQ_MTU,                      1UL ); /* TLS 1.3 CertificateVerify payload or vote history file body */
    1091           0 :   /**/               fd_topob_link( topo, "sign_votor",    "sign_votor",    128UL,                                    FD_BLS_SIG_SZ,                                 1UL ); /* ed25519 sig (TLS) or BLS sig (vote) */
    1092           0 :   FOR(net_tile_cnt)  fd_topos_net_rx_link( topo, "net_votor", i, config->net.ingress_buffer_size );
    1093             : 
    1094           0 :   /**/               fd_topob_tile_in (   topo, "votor",  0UL,          "metric_in", "replay_slot",   0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
    1095           0 :   /**/               fd_topob_tile_in (   topo, "votor",  0UL,          "metric_in", "replay_epoch",  0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
    1096           0 :   /**/               fd_topob_tile_in (   topo, "votor",  0UL,          "metric_in", "gossip_ciaddr", 0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
    1097           0 :   /**/               fd_topob_tile_in (   topo, "votor",  0UL,          "metric_in", "ipecho_out",    0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   );
    1098           0 :   FOR(net_tile_cnt)  fd_topob_tile_in (   topo, "votor",  0UL,          "metric_in", "net_votor",     i,            FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   ); /* No reliable consumers of networking fragments, may be dropped or overrun */
    1099             : 
    1100             :   /* Votor's first two outputs must be votor_out and votor_net. */
    1101           0 :   /**/               fd_topob_tile_out(   topo, "votor",  0UL,                       "votor_out",     0UL                                                  );
    1102           0 :   /**/               fd_topob_tile_out(   topo, "votor",  0UL,                       "votor_net",     0UL                                                  );
    1103           0 :   /**/               fd_topos_tile_in_net( topo,                        "metric_in", "votor_net",     0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_POLLED   ); /* No reliable consumers of networking fragments, may be dropped or overrun */
    1104             : 
    1105           0 :   /**/               fd_topob_tile_in (   topo, "rotor",  0UL,          "metric_in", "votor_out",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   ); /* certified blocks to repair */
    1106           0 :   /**/               fd_topob_tile_in (   topo, "replay", 0UL,          "metric_in", "votor_out",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
    1107           0 :   if( config->tiles.gui.enabled ) {
    1108           0 :     /**/             fd_topob_tile_in (   topo, "gui",    0UL,          "metric_in", "votor_out",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
    1109           0 :   }
    1110           0 :   if( rpc_enabled ) {
    1111           0 :     /**/             fd_topob_tile_in (   topo, "rpc",    0UL,          "metric_in", "votor_out",     0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
    1112           0 :   }
    1113             : 
    1114           0 :   /**/               fd_topob_tile_in (   topo, "sign",   0UL,          "metric_in", "votor_sign",    0UL,          FD_TOPOB_RELIABLE,   FD_TOPOB_POLLED   );
    1115           0 :   /**/               fd_topob_tile_out(   topo, "votor",  0UL,                       "votor_sign",    0UL                                                  );
    1116           0 :   /**/               fd_topob_tile_in (   topo, "votor",  0UL,          "metric_in", "sign_votor",    0UL,          FD_TOPOB_UNRELIABLE, FD_TOPOB_UNPOLLED );
    1117           0 :   /**/               fd_topob_tile_out(   topo, "sign",   0UL,                       "sign_votor",    0UL                                                  );
    1118             : 
    1119             :   /* Grant the admin tile access to every keyswitch object in the
    1120             :      topology for add authorized voters and set identity. */
    1121           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
    1122           0 :     if( topo->tiles[ i ].id_keyswitch_obj_id!=ULONG_MAX ) fd_topob_tile_uses( topo, admin_tile, &topo->objs[ topo->tiles[ i ].id_keyswitch_obj_id ], FD_SHMEM_JOIN_MODE_READ_WRITE );
    1123           0 :     if( topo->tiles[ i ].av_keyswitch_obj_id!=ULONG_MAX ) fd_topob_tile_uses( topo, admin_tile, &topo->objs[ topo->tiles[ i ].av_keyswitch_obj_id ], FD_SHMEM_JOIN_MODE_READ_WRITE );
    1124           0 :   }
    1125             : 
    1126           0 :   if( 0==strcmp( config->net.provider, "mlx5" ) ) {
    1127           0 :     ulong net_tile_id = fd_topo_find_tile( topo, fd_net_tile_name( config->net.provider ), 0UL );
    1128           0 :     FD_TEST( net_tile_id!=ULONG_MAX );
    1129           0 :     fd_topos_sock_lo( topo, &topo->tiles[ net_tile_id ] );
    1130           0 :   }
    1131             : 
    1132             :   /* Auto layout must run after all fd_topob_tile() calls so every tile gets a blocklist-aware CPU assignment. */
    1133           0 :   if( FD_UNLIKELY( is_auto_affinity ) ) fd_topob_auto_layout( topo );
    1134             : 
    1135           0 :   ulong fec_set_cnt = fd_shred_tile_fec_set_cnt( FD_SHRED_FIREDANCER_FEC_EXPOSURE,
    1136           0 :                                                   config->tiles.shred.max_pending_shred_sets );
    1137           0 :   ulong store_fec_set_cnt = shred_tile_cnt*fec_set_cnt;
    1138             : 
    1139             :   /* store_fec_max is the maximum number of FEC sets Store retains.
    1140             : 
    1141             :       With Alpenglow, Store is sized to rotor's window of
    1142             :       N = max_live_slots slots, each of which can hold up to
    1143             :       fec_sets_per_slot FEC sets per version of its block.  The number of versions in the window
    1144             :       is bounded as follows.
    1145             : 
    1146             :       Assume 20% of stake is malicious, every malicious leader
    1147             :       equivocates AG_EQVOC_BLOCK_HASH_MAX (7) versions of each of its
    1148             :       slots, and honest leaders produce one.  The expected number of
    1149             :       versions is then (0.8 + 0.2*7)*N = 2.2*N.  In general, bounding
    1150             :       P(V > budget) to z standard deviations needs a budget of
    1151             :       ~N*(2.2 + 4.8*z/sqrt(N)).
    1152             : 
    1153             :       We size for 2.5*N (FD_ROTOR_BLK_VERSION_NUM/DEN, the same factor
    1154             :       rotor sizes its blk pool with, see fd_rotor_blk_max), which leaves
    1155             :       0.3*N of headroom, ie. ~0.0625*sqrt(N) standard deviations.  The
    1156             :       probability that a window holds more than 2.5*N versions is:
    1157             : 
    1158             :         N =  2048  ~2.5e-3
    1159             :         N =  4096  ~4.2e-5
    1160             :         N = 30000  ~3e-26
    1161             : 
    1162             :       This is for a uniformly random window.  The leader schedule is
    1163             :       known an epoch in advance, so an adversary can target the densest
    1164             :       window in the epoch, which is somewhat worse.
    1165             : 
    1166             :       Fixed 32-data-shred sets need 1024 FEC sets per slot; legacy
    1167             :       variable sets can contain one data shred and need up to 32768. */
    1168             : 
    1169           0 :   ulong fec_sets_per_slot = fd_ulong_if( config->firedancer.development.fixed_fec_sets,
    1170           0 :                                          config->limits.max_shreds_per_block/FD_FEC_SHRED_CNT, config->limits.max_shreds_per_block );
    1171           0 :   ulong store_fec_max = fd_rotor_blk_max( config->firedancer.runtime.max_live_slots ) * fec_sets_per_slot; /* every FEC set of every blk rotor holds */
    1172             : 
    1173             :   /* 32 shreds * 995 payload bytes = 31840 bytes with fixed_fec_sets = true
    1174             :      67 shreds * 955 payload bytes = 63985 bytes with fixed_fec_sets = false */
    1175             : 
    1176           0 :   ulong store_fec_data_max = fd_ulong_if( config->firedancer.development.fixed_fec_sets, 31840UL, 63985UL );
    1177           0 :   fd_topo_obj_t * store_obj = setup_topo_store( topo, "store", store_fec_max, store_fec_data_max,
    1178           0 :                                                 rserve_enabled ? config->tiles.rserve.shred_storage_limit_gib : 0UL,
    1179           0 :                                                 config->tiles.shred.shred_cache_size_mib,
    1180           0 :                                                 store_fec_set_cnt,
    1181           0 :                                                 config->limits.max_shreds_per_block,
    1182           0 :                                                 config->paths.shredb,
    1183           0 :                                                 shred_tile_cnt );
    1184           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 );
    1185           0 :   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1186           0 :   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "rotor", 0UL ) ], store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE ); /* rotor */
    1187           0 :   if( rserve_enabled ) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "rserve", 0UL ) ], store_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1188           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, store_obj->id, "store" ) );
    1189             : 
    1190           0 :   fd_topo_obj_t * txncache_obj = setup_topo_txncache( topo, "txncache", config->firedancer.runtime.max_live_slots, 2UL*config->limits.max_txn_per_slot /* sig + message hash */ );
    1191           0 :   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1192           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
    1193           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapin", 0UL ) ], txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1194           0 :   }
    1195           0 :   if( snapmk_enabled ) {
    1196           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapmk", 0UL ) ], txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1197           0 :   }
    1198           0 :   FOR(execle_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "execle", i ) ], txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1199           0 :   FOR(execrp_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "execrp", i ) ], txncache_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1200           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, txncache_obj->id, "txncache" ) );
    1201             : 
    1202             :   /* Snapin and genesi are mutually exclusive accdb writers. */
    1203           0 :   ulong accdb_joiners = 3UL+execle_tile_cnt+execrp_tile_cnt+resolv_tile_cnt
    1204           0 :                       + fd_ulong_if( snapshots_enabled, snapin_tile_cnt, 1UL );
    1205           0 :   ulong partition_sz = config->development.accdb.partition_size_gib*(1UL<<30UL);
    1206           0 :   fd_topo_obj_t * accdb_obj = setup_topo_accdb( topo, "accdb_data",
    1207           0 :       config->firedancer.accounts.max_accounts,
    1208           0 :       config->firedancer.runtime.max_live_slots,
    1209           0 :       FD_RUNTIME_MAX_ACC_WRITES_PER_SLOT,
    1210           0 :       8192UL,
    1211           0 :       partition_sz,
    1212           0 :       config->firedancer.accounts.cache_size_gib*(1UL<<30UL),
    1213           0 :       config->tiles.bundle.enabled,
    1214           0 :       accdb_joiners,
    1215           0 :       snapmk_enabled ? config->firedancer.snapshots.max_incremental_snapshot_accounts : 0UL );
    1216           0 :   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "accdb", 0UL ) ], accdb_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1217           0 :   fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "replay", 0UL ) ], accdb_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1218           0 :   if( FD_UNLIKELY( !snapshots_enabled ) ) {
    1219           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "genesi", 0UL ) ], accdb_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1220           0 :   }
    1221           0 :   if( FD_LIKELY( snapshots_enabled ) ) {
    1222           0 :     fd_topo_obj_t * shmem_obj = fd_topob_obj( topo, "snapin_shmem", "snapin_shmem" );
    1223           0 :     FD_TEST( fd_pod_insertf_ulong( topo->props, shmem_obj->id, "snapin_shmem" ) );
    1224             : 
    1225           0 :     fd_topo_obj_t * dc_ticket_obj = fd_topob_obj_named( topo, "fseq", "snapdc", "frame_ticket" );
    1226           0 :     FOR(snapdc_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapdc", i ) ], dc_ticket_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1227             : 
    1228           0 :     FOR(snapin_tile_cnt) {
    1229           0 :       fd_topo_tile_t * snapin_tile = &topo->tiles[ fd_topo_find_tile( topo, "snapin", i ) ];
    1230           0 :       fd_topob_tile_uses( topo, snapin_tile, accdb_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1231           0 :       fd_topob_tile_uses( topo, snapin_tile, shmem_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1232           0 :     }
    1233           0 :   }
    1234           0 :   fd_topo_obj_t * backup_obj = NULL;
    1235           0 :   if( snapmk_enabled ) {
    1236           0 :     ulong backup_obj_id = fd_pod_query_ulong( topo->props, "backup", ULONG_MAX );
    1237           0 :     FD_TEST( backup_obj_id!=ULONG_MAX );
    1238           0 :     backup_obj = &topo->objs[ backup_obj_id ];
    1239             : 
    1240           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapmk", 0UL ) ], accdb_obj,       FD_SHMEM_JOIN_MODE_READ_WRITE );
    1241           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapmk", 0UL ) ], zp_fseq,         FD_SHMEM_JOIN_MODE_READ_WRITE );
    1242           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapmk", 0UL ) ], backup_obj,  FD_SHMEM_JOIN_MODE_READ_WRITE );
    1243           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snaprd", 0UL ) ], accdb_obj,       FD_SHMEM_JOIN_MODE_READ_ONLY  );
    1244           0 :   }
    1245           0 :   FOR(snapzp_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapzp", i ) ], accdb_obj,       FD_SHMEM_JOIN_MODE_READ_ONLY  );
    1246           0 :   FOR(snapzp_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapzp", i ) ], zp_fseq,         FD_SHMEM_JOIN_MODE_READ_WRITE );
    1247           0 :   FOR(snapzp_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapzp", i ) ], backup_obj,  FD_SHMEM_JOIN_MODE_READ_WRITE );
    1248           0 :   if( snapmk_enabled ) {
    1249           0 :     ulong snaprd_out_link_id = fd_topo_find_link( topo, "snaprd_out", 0UL );
    1250           0 :     FD_TEST( snaprd_out_link_id!=ULONG_MAX );
    1251           0 :     fd_topo_obj_t * snaprd_out_dcache_obj = &topo->objs[ topo->links[ snaprd_out_link_id ].dcache_obj_id ];
    1252           0 :     FOR(snapzp_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "snapzp", i ) ], snaprd_out_dcache_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
    1253           0 :   }
    1254             : 
    1255           0 :   FOR(execle_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "execle", i ) ], accdb_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1256           0 :   FOR(execrp_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "execrp", i ) ], accdb_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1257           0 :   if( FD_UNLIKELY( rpc_enabled ) ) {
    1258           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "rpc", 0UL ) ], accdb_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
    1259           0 :   }
    1260           0 :   FOR(resolv_tile_cnt) fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "resolv", i ) ], accdb_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
    1261           0 :   if( FD_LIKELY( config->tiles.gui.enabled ) ) {
    1262           0 :     fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "gui", 0UL ) ], accdb_obj, FD_SHMEM_JOIN_MODE_READ_ONLY );
    1263           0 :   }
    1264           0 :   FD_TEST( fd_pod_insertf_ulong( topo->props, accdb_obj->id, "accdb" ) );
    1265             : 
    1266             :   /* Each shred tile publishes the highest slot it relayed on turbine
    1267             :      (getMaxRetransmitSlot) into an fseq that rpc reads on request. */
    1268           0 :   if( FD_UNLIKELY( rpc_enabled ) ) {
    1269           0 :     fd_topo_tile_t * rpc_tile = &topo->tiles[ fd_topo_find_tile( topo, "rpc", 0UL ) ];
    1270           0 :     FOR(shred_tile_cnt) {
    1271           0 :       fd_topo_obj_t * fseq_obj = fd_topob_obj( topo, "fseq", "metric" );
    1272           0 :       fd_topob_tile_uses( topo, &topo->tiles[ fd_topo_find_tile( topo, "shred", i ) ], fseq_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1273           0 :       fd_topob_tile_uses( topo, rpc_tile,                                              fseq_obj, FD_SHMEM_JOIN_MODE_READ_ONLY  );
    1274           0 :       FD_TEST( fd_pod_insertf_ulong( topo->props, fseq_obj->id, "shred_rtx.%lu", i ) );
    1275           0 :     }
    1276           0 :   }
    1277             : 
    1278             :   /* Per-RO-joiner accdb epoch fseq objects.  Each read-only accdb
    1279             :      consumer (e.g. the rpc tile) owns a small fseq that it writes its
    1280             :      current epoch into, so that the accdb compaction tile can defer
    1281             :      partition reclamation while the RO consumer is mid-read.  The
    1282             :      accdb tile maps each of these fseqs read-only and passes the
    1283             :      pointer array to fd_accdb_new via external_epoch_slots[]. */
    1284           0 :   if( FD_UNLIKELY( rpc_enabled ) ) {
    1285           0 :     fd_topo_obj_t * fseq_obj = fd_topob_obj( topo, "fseq", "metric" );
    1286           0 :     fd_topo_tile_t * rpc_tile   = &topo->tiles[ fd_topo_find_tile( topo, "rpc",   0UL ) ];
    1287           0 :     fd_topo_tile_t * accdb_tile = &topo->tiles[ fd_topo_find_tile( topo, "accdb", 0UL ) ];
    1288           0 :     fd_topob_tile_uses( topo, rpc_tile,   fseq_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1289           0 :     fd_topob_tile_uses( topo, accdb_tile, fseq_obj, FD_SHMEM_JOIN_MODE_READ_ONLY  );
    1290           0 :     FD_TEST( fd_pod_insertf_ulong( topo->props, fseq_obj->id, "accdb_epoch.rpc" ) );
    1291           0 :   }
    1292           0 :   for( ulong i=0UL; i<resolv_tile_cnt; i++ ) {
    1293           0 :     fd_topo_obj_t * fseq_obj = fd_topob_obj( topo, "fseq", "metric" );
    1294           0 :     fd_topo_tile_t * resolv_tile = &topo->tiles[ fd_topo_find_tile( topo, "resolv", i   ) ];
    1295           0 :     fd_topo_tile_t * accdb_tile  = &topo->tiles[ fd_topo_find_tile( topo, "accdb",  0UL ) ];
    1296           0 :     fd_topob_tile_uses( topo, resolv_tile, fseq_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1297           0 :     fd_topob_tile_uses( topo, accdb_tile,  fseq_obj, FD_SHMEM_JOIN_MODE_READ_ONLY  );
    1298           0 :     FD_TEST( fd_pod_insertf_ulong( topo->props, fseq_obj->id, "accdb_epoch.resolv.%lu", i ) );
    1299           0 :   }
    1300           0 :   for( ulong i=0UL; i<snapzp_tile_cnt; i++ ) {
    1301           0 :     fd_topo_obj_t * fseq_obj = fd_topob_obj( topo, "fseq", "metric" );
    1302           0 :     fd_topo_tile_t * snapzp_tile = &topo->tiles[ fd_topo_find_tile( topo, "snapzp", i   ) ];
    1303           0 :     fd_topo_tile_t * accdb_tile  = &topo->tiles[ fd_topo_find_tile( topo, "accdb",  0UL ) ];
    1304           0 :     fd_topob_tile_uses( topo, snapzp_tile, fseq_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1305           0 :     fd_topob_tile_uses( topo, accdb_tile,  fseq_obj, FD_SHMEM_JOIN_MODE_READ_ONLY  );
    1306           0 :     FD_TEST( fd_pod_insertf_ulong( topo->props, fseq_obj->id, "accdb_epoch.snapzp.%lu", i ) );
    1307           0 :   }
    1308           0 :   if( snapmk_enabled ) {
    1309           0 :     fd_topo_obj_t * fseq_obj = fd_topob_obj( topo, "fseq", "metric" );
    1310           0 :     fd_topo_tile_t * snapmk_tile = &topo->tiles[ fd_topo_find_tile( topo, "snapmk", 0UL ) ];
    1311           0 :     fd_topo_tile_t * accdb_tile  = &topo->tiles[ fd_topo_find_tile( topo, "accdb",  0UL ) ];
    1312           0 :     fd_topob_tile_uses( topo, snapmk_tile, fseq_obj, FD_SHMEM_JOIN_MODE_READ_WRITE );
    1313           0 :     fd_topob_tile_uses( topo, accdb_tile,  fseq_obj, FD_SHMEM_JOIN_MODE_READ_ONLY  );
    1314           0 :     FD_TEST( fd_pod_insert_ulong( topo->props, "accdb_epoch.snapmk", fseq_obj->id ) );
    1315           0 :   }
    1316             : 
    1317           0 :   fd_pod_insert_int( topo->props, "sandbox", config->development.sandbox ? 1 : 0 );
    1318             : 
    1319           0 :   fd_topob_waker( topo );
    1320             : 
    1321           0 :   fd_topob_sleep_finish( topo );
    1322             : 
    1323           0 :   for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
    1324           0 :     fd_topo_configure_tile( &topo->tiles[ i ], config );
    1325           0 :     if( FD_UNLIKELY( !strcmp( topo->tiles[ i ].name, "gui" ) ) ) topo->tiles[ i ].gui.tile_cnt = topo->tile_cnt;
    1326           0 :     if( FD_UNLIKELY( ( !strcmp( topo->tiles[ i ].name, "net" ) || !strcmp( topo->tiles[ i ].name, "sock" ) || !strcmp( topo->tiles[ i ].name, "mlx5" ) ) ) ) {
    1327           0 :       topo->tiles[ i ].net.votor_quic_client_listen_port = config->firedancer.development.votor.quic_client_listen_port;
    1328           0 :       topo->tiles[ i ].net.votor_quic_server_listen_port = config->firedancer.development.votor.quic_server_listen_port;
    1329           0 :     }
    1330           0 :   }
    1331             : 
    1332           0 :   if( FD_LIKELY( telemetry_enabled ) ) {
    1333           0 :     wire_event_links( topo );
    1334             : 
    1335           0 :     fd_topo_tile_t * event_tile = &topo->tiles[ fd_topo_find_tile( topo, "event", 0UL ) ];
    1336           0 :     for( ulong i=0UL; i<topo->tile_cnt; i++ ) {
    1337           0 :       fd_topob_tile_uses( topo, event_tile, &topo->objs[ topo->tiles[ i ].metrics_obj_id ], FD_SHMEM_JOIN_MODE_READ_ONLY );
    1338           0 :     }
    1339           0 :   }
    1340             : 
    1341           0 :   if( FD_LIKELY( telemetry_enabled ) ) {
    1342           0 :     topo->resolved_config_json_len = fd_config_to_json( config, topo->resolved_config_json, sizeof(topo->resolved_config_json) );
    1343           0 :     topo->user_config_json_len     = fd_config_user_toml_to_json( config, topo->user_config_json, sizeof(topo->user_config_json) );
    1344           0 :   }
    1345             : 
    1346           0 :   FOR(net_tile_cnt) fd_topos_net_tile_finish( topo, i );
    1347           0 :   fd_topob_finish( topo, CALLBACKS );
    1348           0 :   config->topo = *topo;
    1349           0 : }
    1350             : 
    1351             : static void
    1352             : parse_listen_addr( char const *    cstr,
    1353             :                    char const *    key,
    1354           0 :                    fd_ip6_addr_t * out ) {
    1355           0 :   if( FD_UNLIKELY( !fd_cstr_to_ip46_addr( cstr, out ) ) )
    1356           0 :     FD_LOG_ERR(( "[%s] `%s` is not a valid IPv4 or IPv6 address", key, cstr ));
    1357           0 :   if( FD_UNLIKELY( fd_ip6_addr_is_scoped( out->addr ) && !out->scope_id ) )
    1358           0 :     FD_LOG_ERR(( "[%s] `%s` is scoped to a network interface, which must be named by a "
    1359           0 :                  "zone ID (e.g. `%s%%eth0`)", key, cstr, cstr ));
    1360           0 : }
    1361             : 
    1362             : static int
    1363           0 : wfs_hash_is_zero( fd_config_t const * config ) {
    1364           0 :   return !strcmp( config->firedancer.consensus.wait_for_supermajority_with_bank_hash, "" );
    1365           0 : }
    1366             : 
    1367             : static void
    1368             : wfs_decode_bank_hash( fd_config_t const * config,
    1369           0 :                       fd_hash_t *         out ) {
    1370           0 :   if( FD_LIKELY( wfs_hash_is_zero( config ) ) ) {
    1371           0 :     memset( out->uc, 0, sizeof(fd_hash_t) );
    1372           0 :   } else if( FD_UNLIKELY( !fd_base58_decode_32( config->firedancer.consensus.wait_for_supermajority_with_bank_hash, out->uc ) ) ) {
    1373           0 :     FD_LOG_ERR(( "[consensus.wait_for_supermajority_with_bank_hash] failed to parse" ));
    1374           0 :   }
    1375           0 : }
    1376             : 
    1377             : void
    1378             : fd_topo_configure_tile( fd_topo_tile_t * tile,
    1379           0 :                         fd_config_t *    config ) {
    1380           0 :   if( FD_UNLIKELY( !strcmp( tile->name, "metric" ) ) ) {
    1381             : 
    1382           0 :     if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.metric.prometheus_listen_address, &tile->metric.prometheus_listen_addr ) ) )
    1383           0 :       FD_LOG_ERR(( "failed to parse prometheus listen address `%s`", config->tiles.metric.prometheus_listen_address ));
    1384           0 :     tile->metric.prometheus_listen_port = config->tiles.metric.prometheus_listen_port;
    1385             : 
    1386           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "event" ) ) ) {
    1387             : 
    1388           0 :     fd_cstr_ncpy( tile->event.identity_key_path, config->paths.identity_key, sizeof(tile->event.identity_key_path) );
    1389           0 :     fd_cstr_ncpy( tile->event.url, config->tiles.event.url, sizeof(tile->event.url) );
    1390           0 :     fd_cstr_ncpy( tile->event.action, config->action, sizeof(tile->event.action) );
    1391           0 :     FD_TEST( fd_cstr_printf_check( tile->event.accounts_path,  sizeof(tile->event.accounts_path),  NULL, "%s", config->paths.accounts  ) );
    1392           0 :     FD_TEST( fd_cstr_printf_check( tile->event.snapshots_path, sizeof(tile->event.snapshots_path), NULL, "%s", config->paths.snapshots ) );
    1393           0 :     FD_TEST( fd_cstr_printf_check( tile->event.log_path,       sizeof(tile->event.log_path),       NULL, "%s", config->log.path        ) );
    1394           0 :     FD_TEST( fd_cstr_printf_check( tile->event.shredb_path,    sizeof(tile->event.shredb_path),    NULL, "%s", config->paths.shredb    ) );
    1395           0 :     FD_TEST( fd_cstr_printf_check( tile->event.guidb_path,     sizeof(tile->event.guidb_path),     NULL, "%s", config->paths.guidb     ) );
    1396           0 :     FD_TEST( fd_cstr_printf_check( tile->event.net_interface,  sizeof(tile->event.net_interface),  NULL, "%s", config->net.interface   ) );
    1397           0 :     tile->event.boot_timestamp_nanos = config->boot_timestamp_nanos;
    1398           0 :     fd_memcpy( tile->event.launch_cpus, config->launch_cpus, sizeof(tile->event.launch_cpus) );
    1399           0 :     FD_TEST( fd_cstr_printf_check( tile->event.launch_cgroup, sizeof(tile->event.launch_cgroup), NULL, "%s", config->launch_cgroup ) );
    1400             : 
    1401           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "net"   ) ||
    1402           0 :                           !strcmp( tile->name, "sock"  ) ||
    1403           0 :                           !strcmp( tile->name, "mlx5" ) ) ) {
    1404             : 
    1405           0 :     tile->net.shred_listen_port                = config->tiles.shred.shred_listen_port;
    1406           0 :     if( config->firedancer.layout.enable_block_production ) {
    1407           0 :       tile->net.quic_transaction_listen_port   = config->tiles.quic.quic_transaction_listen_port;
    1408           0 :       tile->net.legacy_transaction_listen_port = config->tiles.quic.regular_transaction_listen_port;
    1409           0 :     }
    1410           0 :     tile->net.gossip_listen_port               = config->gossip.port;
    1411           0 :     tile->net.repair_client_listen_port        = config->tiles.repair.repair_client_listen_port;
    1412           0 :     tile->net.repair_serve_listen_port         = fd_ushort_if( config->tiles.rserve.enabled, config->tiles.rserve.repair_serve_listen_port, 0 );
    1413             : 
    1414           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "netlnk" ) ) ) {
    1415             : 
    1416           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "ipecho") ) ) {
    1417             : 
    1418           0 :     tile->ipecho.expected_shred_version = config->consensus.expected_shred_version;
    1419           0 :     tile->ipecho.bind_address           = config->net.ip_addr;
    1420           0 :     tile->ipecho.bind_port              = config->gossip.port;
    1421           0 :     tile->ipecho.entrypoints_cnt        = config->gossip.entrypoints_cnt;
    1422           0 :     for( ulong i=0UL; i<tile->ipecho.entrypoints_cnt; i++ )
    1423           0 :       fd_cstr_ncpy( tile->ipecho.entrypoints[ i ], config->gossip.entrypoints[ i ], sizeof(tile->ipecho.entrypoints[ i ]) );
    1424             : 
    1425           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "genesi" ) ) ) {
    1426             : 
    1427           0 :     tile->genesi.validate_genesis_hash = config->firedancer.development.genesis.validate_genesis_hash;
    1428           0 :     tile->genesi.allow_download = config->firedancer.snapshots.genesis_download;
    1429           0 :     fd_cstr_ncpy( tile->genesi.genesis_path, config->paths.genesis, sizeof(tile->genesi.genesis_path) );
    1430           0 :     tile->genesi.expected_shred_version = config->consensus.expected_shred_version;
    1431           0 :     tile->genesi.entrypoints_cnt        = config->gossip.entrypoints_cnt;
    1432           0 :     for( ulong i=0UL; i<tile->genesi.entrypoints_cnt; i++ )
    1433           0 :       fd_cstr_ncpy( tile->genesi.entrypoints[ i ], config->gossip.entrypoints[ i ], sizeof(tile->genesi.entrypoints[ i ]) );
    1434             : 
    1435           0 :     tile->genesi.has_expected_genesis_hash = !!strcmp( config->consensus.expected_genesis_hash, "" );
    1436             : 
    1437           0 :     if( FD_UNLIKELY( strcmp( config->consensus.expected_genesis_hash, "" ) && !fd_base58_decode_32( config->consensus.expected_genesis_hash, tile->genesi.expected_genesis_hash ) ) ) {
    1438           0 :       FD_LOG_ERR(( "failed to decode [consensus.expected_genesis_hash] \"%s\" as base58", config->consensus.expected_genesis_hash ));
    1439           0 :     }
    1440             : 
    1441           0 :     tile->genesi.target_gid      = config->gid;
    1442           0 :     tile->genesi.target_uid      = config->uid;
    1443             : 
    1444           0 :     tile->genesi.max_live_slots   = config->firedancer.runtime.max_live_slots;
    1445           0 :     tile->genesi.accdb_obj_id     = fd_pod_query_ulong( config->topo.props, "accdb", ULONG_MAX );
    1446           0 :     tile->genesi.max_message_size = config->firedancer.development.genesis.max_file_size_mib << 20;
    1447           0 :     FD_TEST( tile->genesi.accdb_obj_id!=ULONG_MAX );
    1448             : 
    1449           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "admin" ) ) ) {
    1450             : 
    1451           0 :     fd_cstr_ncpy( tile->admin.identity_key_path, config->paths.identity_key, sizeof(tile->admin.identity_key_path) );
    1452             : 
    1453           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "gossvf") ) ) {
    1454             : 
    1455           0 :     fd_cstr_ncpy( tile->gossvf.identity_key_path, config->paths.identity_key, sizeof(tile->gossvf.identity_key_path) );
    1456           0 :     tile->gossvf.tcache_depth          = 1<<22UL; /* TODO: user defined option */
    1457           0 :     tile->gossvf.shred_version         = 0U;
    1458           0 :     tile->gossvf.allow_private_address = config->development.gossip.allow_private_address;
    1459           0 :     tile->gossvf.boot_timestamp_nanos   = config->boot_timestamp_nanos;
    1460             : 
    1461           0 :     tile->gossvf.entrypoints_cnt = config->gossip.entrypoints_cnt;
    1462           0 :     for( ulong i=0UL; i<tile->gossvf.entrypoints_cnt; i++ ) {
    1463           0 :       fd_cstr_ncpy( tile->gossvf.entrypoints[ i ], config->gossip.entrypoints[ i ], sizeof(tile->gossvf.entrypoints[ i ]) );
    1464           0 :     }
    1465             : 
    1466           0 :     fd_cstr_ncpy( tile->gossvf.gossip_host, config->firedancer.gossip.host, sizeof(tile->gossvf.gossip_host) );
    1467           0 :     tile->gossvf.gossip_addr.addr = config->net.ip_addr;
    1468           0 :     tile->gossvf.gossip_addr.port = fd_ushort_bswap( config->gossip.port );
    1469             : 
    1470           0 :     tile->gossvf.src_addr.addr = config->net.ip_addr;
    1471           0 :     tile->gossvf.src_addr.port = fd_ushort_bswap( config->gossip.port );
    1472             : 
    1473           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "gossip" ) ) ) {
    1474             : 
    1475           0 :     fd_cstr_ncpy( tile->gossip.gossip_host, config->firedancer.gossip.host, sizeof(tile->gossip.gossip_host) );
    1476           0 :     tile->gossip.net_ip_addr            = config->net.ip_addr;
    1477           0 :     tile->gossip.ip_addr                = config->net.ip_addr;
    1478           0 :     tile->gossip.bind_ip_addr           = config->net.ip_addr;
    1479           0 :     fd_cstr_ncpy( tile->gossip.identity_key_path, config->paths.identity_key, sizeof(tile->gossip.identity_key_path) );
    1480           0 :     tile->gossip.expected_shred_version = config->consensus.expected_shred_version;
    1481           0 :     tile->gossip.max_entries            = config->tiles.gossip.max_entries;
    1482           0 :     tile->gossip.boot_timestamp_nanos   = config->boot_timestamp_nanos;
    1483             : 
    1484           0 :     tile->gossip.wait_for_supermajority_at_slot      = config->firedancer.consensus.wait_for_supermajority_at_slot;
    1485           0 :     tile->gossip.wait_for_supermajority_hash_is_zero = wfs_hash_is_zero( config );
    1486             : 
    1487           0 :     tile->gossip.ports.gossip           = config->gossip.port;
    1488           0 :     tile->gossip.ports.tvu              = config->tiles.shred.shred_listen_port;
    1489           0 :     tile->gossip.ports.tpu              = config->tiles.quic.regular_transaction_listen_port;
    1490           0 :     tile->gossip.ports.tpu_quic         = config->tiles.quic.quic_transaction_listen_port;
    1491           0 :     tile->gossip.ports.repair           = config->tiles.repair.repair_client_listen_port;
    1492           0 :     tile->gossip.ports.rserve           = fd_ushort_if( config->tiles.rserve.enabled, config->tiles.rserve.repair_serve_listen_port, 0 );
    1493           0 :     tile->gossip.ports.votor            = config->firedancer.development.votor.quic_server_listen_port;
    1494             : 
    1495           0 :     tile->gossip.entrypoints_cnt        = config->gossip.entrypoints_cnt;
    1496           0 :     for( ulong i=0UL; i<tile->gossip.entrypoints_cnt; i++ ) {
    1497           0 :       fd_cstr_ncpy( tile->gossip.entrypoints[ i ], config->gossip.entrypoints[ i ], sizeof(tile->gossip.entrypoints[ i ]) );
    1498           0 :     }
    1499             : 
    1500           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapct" ) ) ) {
    1501             : 
    1502           0 :     fd_memcpy( tile->snapct.snapshots_path, config->paths.snapshots, PATH_MAX );
    1503           0 :     tile->snapct.entrypoints_cnt = fd_ulong_min( config->gossip.entrypoints_cnt, FD_TOPO_GOSSIP_ENTRYPOINTS_MAX );
    1504           0 :     for( ulong i=0UL; i<tile->snapct.entrypoints_cnt; i++ ) {
    1505           0 :       fd_cstr_ncpy( tile->snapct.entrypoints[ i ], config->gossip.entrypoints[ i ], sizeof(tile->snapct.entrypoints[ i ]) );
    1506           0 :     }
    1507           0 :     tile->snapct.sources.max_local_full_effective_age = config->firedancer.snapshots.sources.max_local_full_effective_age;
    1508           0 :     tile->snapct.sources.max_local_incremental_age    = config->firedancer.snapshots.sources.max_local_incremental_age;
    1509           0 :     tile->snapct.incremental_snapshots                = config->firedancer.snapshots.incremental_snapshots;
    1510           0 :     tile->snapct.max_full_snapshots_to_keep           = config->firedancer.snapshots.max_full_snapshots_to_keep;
    1511           0 :     tile->snapct.max_incremental_snapshots_to_keep    = config->firedancer.snapshots.max_incremental_snapshots_to_keep;
    1512           0 :     tile->snapct.max_retry_abort                      = config->firedancer.snapshots.max_retry_abort;
    1513           0 :     tile->snapct.wait_for_peers_timeout_nanos         = (long)( config->firedancer.snapshots.wait_for_peers_timeout_seconds * (ulong)1e9 );
    1514           0 :     tile->snapct.wfs_slot                             = config->firedancer.consensus.wait_for_supermajority_at_slot;
    1515           0 :     tile->snapct.wfs_hash_is_zero                     = wfs_hash_is_zero( config );
    1516           0 :     tile->snapct.wfs_shred_version                    = config->consensus.expected_shred_version;
    1517           0 :     tile->snapct.sources.gossip.allow_any             = config->firedancer.snapshots.sources.gossip.allow_any;
    1518           0 :     tile->snapct.sources.gossip.allow_list_cnt        = config->firedancer.snapshots.sources.gossip.allow_list_cnt;
    1519           0 :     tile->snapct.sources.gossip.block_list_cnt        = config->firedancer.snapshots.sources.gossip.block_list_cnt;
    1520           0 :     tile->snapct.sources.servers_cnt                  = config->firedancer.snapshots.sources.servers_cnt;
    1521           0 :     for( ulong i=0UL; i<tile->snapct.sources.gossip.allow_list_cnt; i++ ) {
    1522           0 :       if( FD_UNLIKELY( !fd_base58_decode_32( config->firedancer.snapshots.sources.gossip.allow_list[ i ], tile->snapct.sources.gossip.allow_list[ i ].uc ) ) ) {
    1523           0 :         FD_LOG_ERR(( "[snapshots.sources.gossip.allow_list[%lu]] invalid (%s)", i, config->firedancer.snapshots.sources.gossip.allow_list[ i ] ));
    1524           0 :       }
    1525           0 :     }
    1526           0 :     for( ulong i=0UL; i<tile->snapct.sources.gossip.block_list_cnt; i++ ) {
    1527           0 :       if( FD_UNLIKELY( !fd_base58_decode_32( config->firedancer.snapshots.sources.gossip.block_list[ i ], tile->snapct.sources.gossip.block_list[ i ].uc ) ) ) {
    1528           0 :         FD_LOG_ERR(( "[snapshots.sources.gossip.block_list[%lu]] invalid (%s)", i, config->firedancer.snapshots.sources.gossip.block_list[ i ] ));
    1529           0 :       }
    1530           0 :     }
    1531             : 
    1532           0 :     for( ulong i=0UL; i<tile->snapct.sources.servers_cnt; i++ ) {
    1533           0 :       fd_cstr_ncpy( tile->snapct.sources.servers[ i ],
    1534           0 :                     config->firedancer.snapshots.sources.servers[ i ],
    1535           0 :                     sizeof(tile->snapct.sources.servers[ i ]) );
    1536           0 :     }
    1537           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapld" ) ) ) {
    1538             : 
    1539           0 :     fd_memcpy( tile->snapld.snapshots_path, config->paths.snapshots, PATH_MAX );
    1540           0 :     tile->snapld.incremental_snapshots             = config->firedancer.snapshots.incremental_snapshots;
    1541           0 :     tile->snapld.min_download_speed_mibs           = config->firedancer.snapshots.min_download_speed_mibs;
    1542           0 :     tile->snapld.wfs_slot                          = config->firedancer.consensus.wait_for_supermajority_at_slot;
    1543           0 :     tile->snapld.wfs_hash_is_zero                  = wfs_hash_is_zero( config );
    1544           0 :     tile->snapld.wfs_shred_version                 = config->consensus.expected_shred_version;
    1545             : 
    1546           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapdc" ) ) ) {
    1547             : 
    1548           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapin" ) ) ) {
    1549             : 
    1550           0 :     tile->snapin.wait_for_supermajority_at_slot = config->firedancer.consensus.wait_for_supermajority_at_slot;
    1551           0 :     wfs_decode_bank_hash( config, &tile->snapin.wait_for_supermajority_with_bank_hash );
    1552           0 :     tile->snapin.expected_shred_version = config->consensus.expected_shred_version;
    1553           0 :     tile->snapin.max_live_slots  = config->firedancer.runtime.max_live_slots;
    1554           0 :     tile->snapin.max_txn_per_slot = config->limits.max_txn_per_slot;
    1555           0 :     tile->snapin.alpenglow        = 1;
    1556           0 :     tile->snapin.accdb_obj_id = fd_pod_query_ulong( config->topo.props, "accdb", ULONG_MAX );
    1557           0 :     tile->snapin.txncache_obj_id = fd_pod_query_ulong( config->topo.props, "txncache", ULONG_MAX );
    1558           0 :     tile->snapin.banks_obj_id = fd_pod_query_ulong( config->topo.props, "banks", ULONG_MAX );
    1559           0 :     tile->snapin.shmem_obj_id = fd_pod_query_ulong( config->topo.props, "snapin_shmem", ULONG_MAX );
    1560             : 
    1561           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "rotor" ) ) ) {
    1562           0 :     tile->rotor.slot_max = config->firedancer.runtime.max_live_slots;
    1563           0 :     tile->rotor.fec_max  = fd_pod_queryf_ulong( config->topo.props, ULONG_MAX, "obj.%lu.fec_max", fd_pod_query_ulong( config->topo.props, "store", ULONG_MAX ) ); /* as many FEC sets as Store */
    1564           0 :     tile->rotor.max_shreds_per_block = config->limits.max_shreds_per_block;
    1565           0 :     tile->rotor.repair_client_listen_port = config->tiles.repair.repair_client_listen_port;
    1566           0 :     tile->rotor.allow_private_address = config->development.gossip.allow_private_address;
    1567             : 
    1568           0 :     for( ulong i=0; i<tile->in_cnt; i++ ) {
    1569           0 :       if( !strcmp( config->topo.links[ tile->in_link_id[ i ] ].name, "sign_repair" ) ) {
    1570           0 :         tile->rotor.repair_sign_depth = config->topo.links[ tile->in_link_id[ i ] ].depth;
    1571           0 :         break;
    1572           0 :       }
    1573           0 :     }
    1574           0 :     tile->rotor.repair_sign_cnt = config->firedancer.layout.sign_tile_count - 1; /* -1 because this excludes the keyguard client */
    1575           0 :     fd_cstr_ncpy( tile->rotor.identity_key_path, config->paths.identity_key, sizeof(tile->rotor.identity_key_path) );
    1576           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "rserve" ) ) ) {
    1577           0 :     tile->rserve.repair_serve_listen_port = config->tiles.rserve.repair_serve_listen_port;
    1578           0 :     tile->rserve.max_shreds_per_block = config->limits.max_shreds_per_block;
    1579           0 :     tile->rserve.ping_cache_entries = 1UL<<16; /* TODO: Configure this from some global metric? */
    1580           0 :     tile->rserve.blockdb_max = 1UL<<15; /* ~20.6 KiB each. TODO: make configurable */
    1581           0 :     fd_cstr_ncpy( tile->rserve.identity_key_path, config->paths.identity_key, sizeof(tile->rserve.identity_key_path) );
    1582             : 
    1583           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "replay" ) )) {
    1584             : 
    1585             :     /* Please maintain same field order as fd_topo.h */
    1586             : 
    1587           0 :     tile->replay.fec_max = config->firedancer.runtime.max_live_slots *
    1588           0 :                            fd_ulong_if( config->firedancer.development.fixed_fec_sets,
    1589           0 :                                         config->limits.max_shreds_per_block/FD_FEC_SHRED_CNT, config->limits.max_shreds_per_block );
    1590           0 :     tile->replay.boot_timestamp_nanos = config->boot_timestamp_nanos;
    1591             : 
    1592           0 :     tile->replay.accdb_obj_id = fd_pod_query_ulong( config->topo.props, "accdb", ULONG_MAX );
    1593           0 :     FD_TEST( tile->replay.accdb_obj_id !=ULONG_MAX );
    1594           0 :     tile->replay.txncache_obj_id = fd_pod_query_ulong( config->topo.props, "txncache", ULONG_MAX );
    1595           0 :     FD_TEST( tile->replay.txncache_obj_id !=ULONG_MAX );
    1596             : 
    1597           0 :     fd_cstr_ncpy( tile->replay.identity_key_path, config->paths.identity_key, sizeof(tile->replay.identity_key_path) );
    1598           0 :     tile->replay.ip_addr = config->net.ip_addr;
    1599           0 :     fd_cstr_ncpy( tile->replay.vote_account_path, config->paths.vote_account, sizeof(tile->replay.vote_account_path) );
    1600             : 
    1601           0 :     tile->replay.expected_shred_version = config->consensus.expected_shred_version;
    1602           0 :     tile->replay.wait_for_vote_to_start_leader = config->consensus.wait_for_vote_to_start_leader;
    1603           0 :     tile->replay.alpenglow = 1;
    1604             : 
    1605           0 :     tile->replay.sched_depth = config->tiles.replay.max_transaction_lookahead_buffer_size;
    1606           0 :     wfs_decode_bank_hash( config, &tile->replay.wait_for_supermajority_with_bank_hash );
    1607           0 :     tile->replay.wait_for_supermajority_at_slot = config->firedancer.consensus.wait_for_supermajority_at_slot;
    1608             : 
    1609           0 :     tile->replay.max_live_slots = config->firedancer.runtime.max_live_slots;
    1610           0 :     tile->replay.genesis_max_message_size = config->firedancer.development.genesis.max_file_size_mib << 20;
    1611           0 :     tile->replay.full_snapshot_interval_blocks        = config->firedancer.snapshots.full_snapshot_interval_blocks;
    1612           0 :     tile->replay.incremental_snapshot_interval_blocks = config->firedancer.snapshots.incremental_snapshot_interval_blocks;
    1613             : 
    1614           0 :     fd_cstr_ncpy( tile->replay.genesis_path, config->paths.genesis, sizeof(tile->replay.genesis_path) );
    1615             : 
    1616           0 :     tile->replay.max_txn_per_slot     = config->limits.max_txn_per_slot;
    1617           0 :     tile->replay.max_shreds_per_block = config->limits.max_shreds_per_block;
    1618             : 
    1619             :     /* not specified by [tiles.replay] */
    1620             : 
    1621           0 :     tile->replay.capture_start_slot = config->capture.capture_start_slot;
    1622           0 :     fd_cstr_ncpy( tile->replay.solcap_capture, config->capture.solcap_capture, sizeof(tile->replay.solcap_capture) );
    1623           0 :     fd_cstr_ncpy( tile->replay.dump_proto_dir, config->capture.dump_proto_dir, sizeof(tile->replay.dump_proto_dir) );
    1624           0 :     tile->replay.dump_block_to_pb = config->capture.dump_block_to_pb;
    1625           0 :     tile->replay.report_runtime_diffs = config->development.event.report_runtime_diffs;
    1626             : 
    1627           0 :     if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
    1628           0 : #define PARSE_BUNDLE_PUBKEY( _tile, f ) \
    1629           0 :       if( FD_UNLIKELY( !fd_base58_decode_32( config->tiles.bundle.f, tile->_tile.bundle.f ) ) )  \
    1630           0 :         FD_LOG_ERR(( "[tiles.bundle.enabled] set to true, but failed to parse [tiles.bundle."#f"] %s", config->tiles.bundle.f ));
    1631           0 :       tile->replay.bundle.enabled = 1;
    1632           0 :       PARSE_BUNDLE_PUBKEY( replay, tip_distribution_program_addr );
    1633           0 :       PARSE_BUNDLE_PUBKEY( replay, tip_payment_program_addr      );
    1634           0 :       fd_cstr_ncpy( tile->replay.bundle.vote_account_path, config->paths.vote_account, sizeof(tile->replay.bundle.vote_account_path) );
    1635           0 :     } else {
    1636           0 :       fd_memset( &tile->replay.bundle, '\0', sizeof(tile->replay.bundle) );
    1637           0 :     }
    1638             : 
    1639           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "execrp" ) ) ) {
    1640             : 
    1641           0 :     tile->execrp.txncache_obj_id  = fd_pod_query_ulong( config->topo.props, "txncache",  ULONG_MAX ); FD_TEST( tile->execrp.txncache_obj_id !=ULONG_MAX );
    1642           0 :     tile->execrp.progcache_obj_id = fd_pod_query_ulong( config->topo.props, "progcache", ULONG_MAX ); FD_TEST( tile->execrp.progcache_obj_id!=ULONG_MAX );
    1643           0 :     tile->execrp.accdb_obj_id     = fd_pod_query_ulong( config->topo.props, "accdb",     ULONG_MAX ); FD_TEST( tile->execrp.accdb_obj_id    !=ULONG_MAX );
    1644             : 
    1645           0 :     tile->execrp.max_live_slots  = config->firedancer.runtime.max_live_slots;
    1646             : 
    1647           0 :     tile->execrp.capture_start_slot = config->capture.capture_start_slot;
    1648           0 :     fd_cstr_ncpy( tile->execrp.solcap_capture, config->capture.solcap_capture, sizeof(tile->execrp.solcap_capture) );
    1649           0 :     fd_cstr_ncpy( tile->execrp.dump_proto_dir, config->capture.dump_proto_dir, sizeof(tile->execrp.dump_proto_dir) );
    1650           0 :     fd_cstr_ncpy( tile->execrp.dump_syscall_name_filter, config->capture.dump_syscall_name_filter, sizeof(tile->execrp.dump_syscall_name_filter) );
    1651           0 :     fd_cstr_ncpy( tile->execrp.dump_instr_program_id_filter, config->capture.dump_instr_program_id_filter, sizeof(tile->execrp.dump_instr_program_id_filter) );
    1652           0 :     tile->execrp.dump_instr_to_pb = config->capture.dump_instr_to_pb;
    1653           0 :     tile->execrp.dump_txn_to_pb = config->capture.dump_txn_to_pb;
    1654           0 :     tile->execrp.dump_txn_as_fixture = config->capture.dump_txn_as_fixture;
    1655           0 :     tile->execrp.dump_syscall_to_pb = config->capture.dump_syscall_to_pb;
    1656           0 :     tile->execrp.report_runtime_diffs = config->development.event.report_runtime_diffs;
    1657             : 
    1658           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "votor" ) ) ) {
    1659           0 :     tile->votor.quic_client_listen_port = config->firedancer.development.votor.quic_client_listen_port;
    1660           0 :     tile->votor.quic_server_listen_port = config->firedancer.development.votor.quic_server_listen_port;
    1661           0 :     tile->votor.ip_addr                 = config->net.ip_addr;
    1662           0 :     tile->votor.max_live_slots          = config->firedancer.runtime.max_live_slots;
    1663           0 :     fd_cstr_ncpy( tile->votor.identity_key_path, config->paths.identity_key, sizeof(tile->votor.identity_key_path) );
    1664           0 :     fd_cstr_ncpy( tile->votor.vote_history_path, config->paths.vote_history, sizeof(tile->votor.vote_history_path) );
    1665           0 :     tile->votor.target_gid = config->gid;
    1666           0 :     tile->votor.target_uid = config->uid;
    1667           0 :     tile->votor.authorized_voter_paths_cnt = config->firedancer.paths.authorized_voter_paths_cnt;
    1668           0 :     tile->votor.wait_for_supermajority_at_slot      = config->firedancer.consensus.wait_for_supermajority_at_slot;
    1669           0 :     tile->votor.wait_for_supermajority_hash_is_zero = wfs_hash_is_zero( config );
    1670           0 :     tile->votor.expected_shred_version              = config->consensus.expected_shred_version;
    1671             : 
    1672           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "accdb" ) ) ) {
    1673             : 
    1674           0 :     tile->accdb.accdb_obj_id = fd_pod_query_ulong( config->topo.props, "accdb", ULONG_MAX );
    1675           0 :     tile->accdb.max_live_slots = config->firedancer.runtime.max_live_slots;
    1676             : 
    1677           0 :     tile->accdb.rpc_epoch_obj_id = fd_pod_query_ulong( config->topo.props, "accdb_epoch.rpc", ULONG_MAX );
    1678             : 
    1679           0 :     tile->accdb.resolv_epoch_obj_cnt = config->firedancer.layout.enable_block_production ? config->firedancer.layout.resolv_tile_count : 0UL;
    1680           0 :     FD_TEST( tile->accdb.resolv_epoch_obj_cnt<=sizeof(tile->accdb.resolv_epoch_obj_ids)/sizeof(tile->accdb.resolv_epoch_obj_ids[0]) );
    1681           0 :     for( ulong i=0UL; i<tile->accdb.resolv_epoch_obj_cnt; i++ ) {
    1682           0 :       tile->accdb.resolv_epoch_obj_ids[ i ] = fd_pod_queryf_ulong( config->topo.props, ULONG_MAX, "accdb_epoch.resolv.%lu", i );
    1683           0 :       FD_TEST( tile->accdb.resolv_epoch_obj_ids[ i ]!=ULONG_MAX );
    1684           0 :     }
    1685             : 
    1686           0 :     tile->accdb.snapmk_epoch_obj_id = fd_pod_query_ulong( config->topo.props, "accdb_epoch.snapmk", ULONG_MAX );
    1687             : 
    1688           0 :     tile->accdb.snapzp_epoch_obj_cnt = config->firedancer.layout.enable_snapshot_production
    1689           0 :                                        ? config->firedancer.layout.snapzp_tile_count : 0UL;
    1690           0 :     FD_TEST( tile->accdb.snapzp_epoch_obj_cnt<=sizeof(tile->accdb.snapzp_epoch_obj_ids)/sizeof(tile->accdb.snapzp_epoch_obj_ids[0]) );
    1691           0 :     for( ulong i=0UL; i<tile->accdb.snapzp_epoch_obj_cnt; i++ ) {
    1692           0 :       tile->accdb.snapzp_epoch_obj_ids[ i ] = fd_pod_queryf_ulong( config->topo.props, ULONG_MAX, "accdb_epoch.snapzp.%lu", i );
    1693             :       /* might not exist for topos without snapshot creation */
    1694           0 :     }
    1695             : 
    1696           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "quic" ) ) ) {
    1697             : 
    1698           0 :     tile->quic.reasm_cnt                      = config->tiles.quic.txn_reassembly_count;
    1699           0 :     tile->quic.out_depth                      = config->tiles.verify.receive_buffer_size;
    1700           0 :     tile->quic.max_concurrent_connections     = config->tiles.quic.max_concurrent_connections;
    1701           0 :     tile->quic.max_concurrent_handshakes      = config->tiles.quic.max_concurrent_handshakes;
    1702           0 :     tile->quic.quic_transaction_listen_port   = config->tiles.quic.quic_transaction_listen_port;
    1703           0 :     tile->quic.idle_timeout_millis            = config->tiles.quic.idle_timeout_millis;
    1704           0 :     tile->quic.ack_delay_millis               = config->tiles.quic.ack_delay_millis;
    1705           0 :     tile->quic.retry                          = config->tiles.quic.retry;
    1706           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) ) );
    1707             : 
    1708           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "verify" ) ) ) {
    1709             : 
    1710           0 :     tile->verify.tcache_depth = config->tiles.verify.signature_cache_size;
    1711             : 
    1712           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "dedup" ) ) ) {
    1713             : 
    1714           0 :     tile->dedup.tcache_depth = config->tiles.dedup.signature_cache_size;
    1715             : 
    1716           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "resolv" ) ) ) {
    1717             : 
    1718           0 :     tile->resolv.max_live_slots = config->firedancer.runtime.max_live_slots;
    1719           0 :     tile->resolv.accdb_obj_id   = fd_pod_query_ulong( config->topo.props, "accdb", ULONG_MAX );
    1720           0 :     FD_TEST( tile->resolv.accdb_obj_id!=ULONG_MAX );
    1721           0 :     tile->resolv.accdb_epoch_fseq_obj_id = fd_pod_queryf_ulong( config->topo.props, ULONG_MAX, "accdb_epoch.resolv.%lu", tile->kind_id );
    1722           0 :     FD_TEST( tile->resolv.accdb_epoch_fseq_obj_id!=ULONG_MAX );
    1723             : 
    1724           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "pack" ) ) ) {
    1725             : 
    1726           0 :     tile->pack.max_pending_transactions      = config->tiles.pack.max_pending_transactions;
    1727           0 :     tile->pack.execle_tile_count             = config->firedancer.layout.execle_tile_count;
    1728           0 :     tile->pack.max_cost_per_block            = config->limits.max_cost_per_block;
    1729           0 :     tile->pack.max_shreds_per_block          = config->limits.max_shreds_per_block;
    1730           0 :     tile->pack.bench_max_shreds_per_block    = config->development.bench.max_shreds_per_block;
    1731           0 :     tile->pack.use_consumed_cus              = config->tiles.pack.use_consumed_cus;
    1732           0 :     tile->pack.schedule_strategy             = config->tiles.pack.schedule_strategy_enum;
    1733           0 :     tile->pack.acct_blocklist_cnt            = config->tiles.pack.account_blocklist_cnt;
    1734             : 
    1735           0 :     for( ulong i=0UL; i<tile->pack.acct_blocklist_cnt; i++ ) {
    1736           0 :       if( FD_UNLIKELY( NULL==fd_base58_decode_32( config->tiles.pack.account_blocklist[i], tile->pack.acct_blocklist[i].uc ) ) ) {
    1737           0 :         FD_LOG_ERR(( "could not parse account %s at index %lu in [tiles.pack.account_blocklist]", config->tiles.pack.account_blocklist[i], i ));
    1738           0 :       }
    1739           0 :     }
    1740             : 
    1741           0 :     if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
    1742             : 
    1743           0 :       tile->pack.bundle.enabled = 1;
    1744           0 :       PARSE_BUNDLE_PUBKEY( pack, tip_distribution_program_addr );
    1745           0 :       PARSE_BUNDLE_PUBKEY( pack, tip_payment_program_addr      );
    1746           0 :       PARSE_BUNDLE_PUBKEY( pack, tip_distribution_authority    );
    1747           0 :       tile->pack.bundle.commission_bps = config->tiles.bundle.commission_bps;
    1748           0 :       fd_cstr_ncpy( tile->pack.bundle.identity_key_path, config->paths.identity_key, sizeof(tile->pack.bundle.identity_key_path) );
    1749           0 :       fd_cstr_ncpy( tile->pack.bundle.vote_account_path, config->paths.vote_account, sizeof(tile->pack.bundle.vote_account_path) );
    1750           0 :     } else {
    1751           0 :       fd_memset( &tile->pack.bundle, '\0', sizeof(tile->pack.bundle) );
    1752           0 :     }
    1753             : 
    1754           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "execle" ) ) ) {
    1755             : 
    1756           0 :     tile->execle.txncache_obj_id    = fd_pod_query_ulong( config->topo.props, "txncache",  ULONG_MAX ); FD_TEST( tile->execle.txncache_obj_id !=ULONG_MAX );
    1757           0 :     tile->execle.progcache_obj_id   = fd_pod_query_ulong( config->topo.props, "progcache", ULONG_MAX ); FD_TEST( tile->execle.progcache_obj_id!=ULONG_MAX );
    1758           0 :     tile->execle.accdb_obj_id       = fd_pod_query_ulong( config->topo.props, "accdb",     ULONG_MAX ); FD_TEST( tile->execle.accdb_obj_id    !=ULONG_MAX );
    1759           0 :     tile->execle.max_live_slots     = config->firedancer.runtime.max_live_slots;
    1760           0 :     tile->execle.report_runtime_diffs = config->development.event.report_runtime_diffs;
    1761             : 
    1762           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "motor" ) ) ) {
    1763           0 :     fd_cstr_ncpy( tile->motor.identity_key_path, config->paths.identity_key, sizeof(tile->motor.identity_key_path) );
    1764             : 
    1765           0 :     tile->motor.execle_cnt = config->firedancer.layout.execle_tile_count;
    1766           0 :     tile->motor.max_txn_per_slot = config->limits.max_txn_per_slot;
    1767             : 
    1768           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "shred" ) ) ) {
    1769             : 
    1770           0 :     fd_cstr_ncpy( tile->shred.identity_key_path, config->paths.identity_key, sizeof(tile->shred.identity_key_path) );
    1771             : 
    1772           0 :     tile->shred.fec_exposure                  = FD_SHRED_FIREDANCER_FEC_EXPOSURE;
    1773           0 :     tile->shred.fec_resolver_depth            = config->tiles.shred.max_pending_shred_sets;
    1774           0 :     tile->shred.slot_max                      = config->firedancer.runtime.max_live_slots;
    1775           0 :     tile->shred.expected_shred_version        = config->consensus.expected_shred_version;
    1776           0 :     tile->shred.shred_listen_port             = config->tiles.shred.shred_listen_port;
    1777           0 :     tile->shred.max_shreds_per_block          = config->limits.max_shreds_per_block;
    1778           0 :     tile->shred.alpenglow                     = 1;
    1779           0 :     tile->shred.bench_max_shreds_per_block    = config->development.bench.max_shreds_per_block;
    1780           0 :     tile->shred.adtl_dests_retransmit_cnt     = config->tiles.shred.additional_shred_destinations_retransmit_cnt;
    1781           0 :     tile->shred.adtl_dests_leader_cnt         = config->tiles.shred.additional_shred_destinations_leader_cnt;
    1782           0 :     fd_memcpy( tile->shred.adtl_dests_retransmit, config->tiles.shred.additional_shred_destinations_retransmit,
    1783           0 :                tile->shred.adtl_dests_retransmit_cnt*sizeof(tile->shred.adtl_dests_retransmit[ 0 ]) );
    1784           0 :     fd_memcpy( tile->shred.adtl_dests_leader, config->tiles.shred.additional_shred_destinations_leader,
    1785           0 :                tile->shred.adtl_dests_leader_cnt*sizeof(tile->shred.adtl_dests_leader[ 0 ]) );
    1786             : 
    1787           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "sign" ) ) ) {
    1788             : 
    1789           0 :     fd_cstr_ncpy( tile->sign.identity_key_path, config->paths.identity_key, sizeof(tile->sign.identity_key_path) );
    1790             : 
    1791           0 :     tile->sign.authorized_voter_paths_cnt = config->firedancer.paths.authorized_voter_paths_cnt;
    1792           0 :     for( ulong i=0UL; i<tile->sign.authorized_voter_paths_cnt; i++ ) {
    1793           0 :       fd_cstr_ncpy( tile->sign.authorized_voter_paths[ i ], config->firedancer.paths.authorized_voter_paths[ i ], sizeof(tile->sign.authorized_voter_paths[ i ]) );
    1794           0 :     }
    1795           0 :     if( FD_UNLIKELY( config->tiles.bundle.enabled ) ) {
    1796           0 :       PARSE_BUNDLE_PUBKEY( sign, tip_distribution_program_addr );
    1797           0 :       PARSE_BUNDLE_PUBKEY( sign, tip_payment_program_addr      );
    1798           0 :     } else {
    1799             :       /* 0xFF.. is not an invocable program */
    1800           0 :       memset( tile->sign.bundle.tip_distribution_program_addr, '\xFF', 32UL );
    1801           0 :       memset( tile->sign.bundle.tip_payment_program_addr,      '\xFF', 32UL );
    1802           0 :     }
    1803             : 
    1804           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "diag" ) ) ) {
    1805             : 
    1806           0 :     tile->diag.is_voting = strcmp( config->paths.vote_account, "" );
    1807             : 
    1808           0 :     fd_cstr_ncpy( tile->diag.shreds_path,    config->tiles.rserve.enabled                         ? config->paths.shredb    : "", sizeof(tile->diag.shreds_path)    );
    1809           0 :     fd_cstr_ncpy( tile->diag.snapshots_path, config->firedancer.layout.enable_snapshot_production ? config->paths.snapshots : "", sizeof(tile->diag.snapshots_path) );
    1810           0 :     fd_cstr_ncpy( tile->diag.accounts_path,  config->paths.accounts,  sizeof(tile->diag.accounts_path) );
    1811           0 :     fd_cstr_ncpy( tile->diag.gui_path,       config->paths.guidb,     sizeof(tile->diag.gui_path)      );
    1812           0 :     fd_cstr_ncpy( tile->diag.log_path,       config->log.path,        sizeof(tile->diag.log_path)      );
    1813             : 
    1814           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "waker" ) ) ) {
    1815             : 
    1816           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "mwaitx" ) ) ) {
    1817             : 
    1818           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "gui" ) ) ) {
    1819             : 
    1820           0 :     if( FD_UNLIKELY( !fd_cstr_to_ip4_addr( config->tiles.gui.gui_listen_address, &tile->gui.listen_addr ) ) )
    1821           0 :       FD_LOG_ERR(( "failed to parse gui listen address `%s`", config->tiles.gui.gui_listen_address ));
    1822           0 :     tile->gui.listen_port = config->tiles.gui.gui_listen_port;
    1823           0 :     tile->gui.max_txn_per_slot = config->limits.max_txn_per_slot;
    1824           0 :     tile->gui.is_voting = strcmp( config->paths.vote_account, "" );
    1825           0 :     tile->gui.is_alpenglow = 1;
    1826           0 :     fd_cstr_ncpy( tile->gui.cluster, config->cluster, sizeof(tile->gui.cluster) );
    1827           0 :     fd_cstr_ncpy( tile->gui.identity_key_path, config->paths.identity_key, sizeof(tile->gui.identity_key_path) );
    1828           0 :     fd_cstr_ncpy( tile->gui.vote_key_path, config->paths.vote_account, sizeof(tile->gui.vote_key_path) );
    1829           0 :     fd_cstr_ncpy( tile->gui.accounts_database_path, config->paths.accounts, sizeof(tile->gui.accounts_database_path) );
    1830           0 :     fd_cstr_ncpy( tile->gui.gui_database_path, config->paths.guidb, sizeof(tile->gui.gui_database_path) );
    1831           0 :     tile->gui.max_http_connections      = config->tiles.gui.max_http_connections;
    1832           0 :     tile->gui.max_websocket_connections = config->tiles.gui.max_websocket_connections;
    1833           0 :     tile->gui.send_buffer_size_mb       = config->tiles.gui.send_buffer_size_mb;
    1834           0 :     tile->gui.db_size_gib               = config->tiles.gui.db_size_gib;
    1835           0 :     tile->gui.schedule_strategy         = config->tiles.pack.schedule_strategy_enum;
    1836           0 :     tile->gui.websocket_compression     = 1;
    1837           0 :     tile->gui.max_live_slots            = config->firedancer.runtime.max_live_slots;
    1838           0 :     fd_cstr_ncpy( tile->gui.wfs_bank_hash, config->firedancer.consensus.wait_for_supermajority_with_bank_hash, sizeof(tile->gui.wfs_bank_hash) );
    1839           0 :     tile->gui.wfs_slot               = config->firedancer.consensus.wait_for_supermajority_at_slot;
    1840           0 :     tile->gui.expected_shred_version = config->consensus.expected_shred_version;
    1841           0 :     tile->gui.cache_size_gib         = config->firedancer.accounts.cache_size_gib;
    1842           0 :     tile->gui.accdb_obj_id           = fd_pod_query_ulong( config->topo.props, "accdb", ULONG_MAX );
    1843           0 :     FD_TEST( tile->gui.accdb_obj_id!=ULONG_MAX );
    1844             : 
    1845           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "rpc" ) ) ) {
    1846             : 
    1847           0 :     parse_listen_addr( config->tiles.rpc.rpc_listen_address, "tiles.rpc.rpc_listen_address", &tile->rpc.listen_addr );
    1848           0 :     tile->rpc.listen_port = config->tiles.rpc.rpc_listen_port;
    1849           0 :     tile->rpc.delay_startup = config->tiles.rpc.delay_startup;
    1850           0 :     tile->rpc.alpenglow     = 1;
    1851           0 :     tile->rpc.max_http_connections      = config->tiles.rpc.max_http_connections;
    1852           0 :     tile->rpc.max_websocket_connections = config->tiles.rpc.max_websocket_connections;
    1853           0 :     tile->rpc.send_buffer_size_mb       = config->tiles.rpc.send_buffer_size_mb;
    1854             : 
    1855           0 :     tile->rpc.max_live_slots           = config->firedancer.runtime.max_live_slots;
    1856           0 :     tile->rpc.genesis_max_message_size = config->firedancer.development.genesis.max_file_size_mib << 20;
    1857             : 
    1858           0 :     tile->rpc.accdb_obj_id = fd_pod_query_ulong( config->topo.props, "accdb", ULONG_MAX );
    1859           0 :     FD_TEST( tile->rpc.accdb_obj_id!=ULONG_MAX );
    1860           0 :     tile->rpc.accdb_epoch_fseq_obj_id = fd_pod_query_ulong( config->topo.props, "accdb_epoch.rpc", ULONG_MAX );
    1861           0 :     FD_TEST( tile->rpc.accdb_epoch_fseq_obj_id!=ULONG_MAX );
    1862             : 
    1863           0 :     fd_cstr_ncpy( tile->rpc.identity_key_path, config->paths.identity_key, sizeof(tile->rpc.identity_key_path) );
    1864             : 
    1865           0 :     tile->rpc.snapshot_server_enabled = fd_topo_find_tile( &config->topo, "snapsv", 0UL )!=ULONG_MAX;
    1866           0 :     if( FD_LIKELY( tile->rpc.snapshot_server_enabled ) ) {
    1867           0 :       fd_cstr_ncpy( tile->rpc.snapshot_server_host, config->firedancer.gossip.host,
    1868           0 :                     sizeof(tile->rpc.snapshot_server_host) );
    1869             : 
    1870           0 :       uint listen_port = config->firedancer.snapshots.server.http_listen_port;
    1871           0 :       FD_CHECK_ERR( listen_port && listen_port<=USHORT_MAX,
    1872           0 :                     "[snapshots.server.http_listen_port] must be in [1,65535]" );
    1873           0 :       tile->rpc.snapshot_server_port = (ushort)listen_port;
    1874           0 :     }
    1875             : 
    1876           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "backt" ) ) ) {
    1877             : 
    1878           0 :     tile->backtest.root_distance = config->firedancer.development.backtest.root_distance;
    1879           0 :     fd_cstr_ncpy( tile->backtest.ledger_format, config->firedancer.development.ledger_input.format, sizeof(tile->backtest.ledger_format) );
    1880           0 :     fd_cstr_ncpy( tile->backtest.ledger_path, config->firedancer.development.ledger_input.path, PATH_MAX );
    1881           0 :     tile->backtest.end_slot = config->firedancer.development.ledger_input.end_slot;
    1882           0 :     tile->backtest.boot_timestamp_nanos = config->boot_timestamp_nanos;
    1883             : 
    1884           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "bundle" ) ) ) {
    1885           0 :     fd_cstr_ncpy( tile->bundle.url, config->tiles.bundle.url, sizeof(tile->bundle.url) );
    1886           0 :     tile->bundle.url_len = strnlen( tile->bundle.url, sizeof(tile->bundle.url)-1UL );
    1887           0 :     fd_cstr_ncpy( tile->bundle.sni, config->tiles.bundle.tls_domain_name, sizeof(tile->bundle.sni) );
    1888           0 :     tile->bundle.sni_len = strnlen( tile->bundle.sni, sizeof(tile->bundle.sni)-1UL );
    1889           0 :     fd_cstr_ncpy( tile->bundle.identity_key_path, config->paths.identity_key, sizeof(tile->bundle.identity_key_path) );
    1890           0 :     fd_cstr_ncpy( tile->bundle.key_log_path, config->development.bundle.ssl_key_log_file, sizeof(tile->bundle.key_log_path) );
    1891           0 :     tile->bundle.buf_sz = config->development.bundle.buffer_size_kib<<10;
    1892           0 :     tile->bundle.out_depth = config->tiles.verify.receive_buffer_size;
    1893           0 :     tile->bundle.keepalive_interval_nanos = config->tiles.bundle.keepalive_interval_millis * (ulong)1e6;
    1894           0 :     tile->bundle.tls_cert_verify = !!config->tiles.bundle.tls_cert_verify;
    1895             : 
    1896           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "solcap" ) ) ) {
    1897             : 
    1898           0 :     tile->solcap.capture_start_slot = config->capture.capture_start_slot;
    1899           0 :     fd_cstr_ncpy( tile->solcap.solcap_capture, config->capture.solcap_capture, sizeof(tile->solcap.solcap_capture) );
    1900           0 :     tile->solcap.recent_only = config->capture.recent_only;
    1901           0 :     tile->solcap.recent_slots_per_file = config->capture.recent_slots_per_file;
    1902             : 
    1903           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapmk" ) ) ) {
    1904             : 
    1905           0 :     tile->snapmk.accdb_obj_id       = fd_pod_query_ulong( config->topo.props, "accdb",              ULONG_MAX ); FD_TEST( tile->snapmk.accdb_obj_id!=ULONG_MAX );
    1906           0 :     tile->snapmk.accdb_epoch_obj_id = fd_pod_query_ulong( config->topo.props, "accdb_epoch.snapmk", ULONG_MAX ); FD_TEST( tile->snapmk.accdb_epoch_obj_id!=ULONG_MAX );
    1907           0 :     tile->snapmk.visited_set_obj_id = fd_pod_query_ulong( config->topo.props, "backup",         ULONG_MAX ); FD_TEST( tile->snapmk.visited_set_obj_id!=ULONG_MAX );
    1908           0 :     tile->snapmk.banks_obj_id       = fd_pod_query_ulong( config->topo.props, "banks",              ULONG_MAX ); FD_TEST( tile->snapmk.banks_obj_id!=ULONG_MAX );
    1909           0 :     tile->snapmk.zp_fseq_id         = fd_pod_query_ulong( config->topo.props, "snapzp.fseq",        ULONG_MAX ); FD_TEST( tile->snapmk.zp_fseq_id!=ULONG_MAX );
    1910           0 :     tile->snapmk.txncache_obj_id    = fd_pod_query_ulong( config->topo.props, "txncache",           ULONG_MAX ); FD_TEST( tile->snapmk.txncache_obj_id!=ULONG_MAX );
    1911           0 :     tile->snapmk.max_accounts       = config->firedancer.accounts.max_accounts;
    1912           0 :     tile->snapmk.max_live_slots     = config->firedancer.runtime.max_live_slots;
    1913           0 :     tile->snapmk.max_txn_per_slot   = config->limits.max_txn_per_slot;
    1914           0 :     tile->snapmk.max_full_snapshots_to_keep        = config->firedancer.snapshots.max_full_snapshots_to_keep;
    1915           0 :     tile->snapmk.max_incremental_snapshots_to_keep = config->firedancer.snapshots.max_incremental_snapshots_to_keep;
    1916           0 :     fd_cstr_ncpy( tile->snapmk.snapshots_path, config->paths.snapshots, PATH_MAX );
    1917             : 
    1918           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapzp" ) ) ) {
    1919             : 
    1920           0 :     tile->snapzp.accdb_obj_id       = fd_pod_query_ulong( config->topo.props, "accdb",              ULONG_MAX ); FD_TEST( tile->snapzp.accdb_obj_id!=ULONG_MAX );
    1921           0 :     tile->snapzp.accdb_epoch_obj_id = fd_pod_queryf_ulong( config->topo.props, ULONG_MAX, "accdb_epoch.snapzp.%lu", tile->kind_id ); FD_TEST( tile->snapzp.accdb_epoch_obj_id!=ULONG_MAX );
    1922           0 :     tile->snapzp.visited_set_obj_id = fd_pod_query_ulong( config->topo.props, "backup",         ULONG_MAX ); FD_TEST( tile->snapzp.visited_set_obj_id!=ULONG_MAX );
    1923           0 :     tile->snapzp.zp_fseq_id         = fd_pod_query_ulong( config->topo.props, "snapzp.fseq",        ULONG_MAX ); FD_TEST( tile->snapzp.zp_fseq_id!=ULONG_MAX );
    1924           0 :     tile->snapzp.max_live_slots     = config->firedancer.runtime.max_live_slots;
    1925           0 :     tile->snapzp.snap_fd_cnt        = config->firedancer.snapshots.max_full_snapshots_to_keep+
    1926           0 :                                       config->firedancer.snapshots.max_incremental_snapshots_to_keep;
    1927             : 
    1928           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snaprd" ) ) ) {
    1929             : 
    1930           0 :     tile->snaprd.accdb_obj_id = fd_pod_query_ulong( config->topo.props, "accdb", ULONG_MAX );
    1931           0 :     FD_TEST( tile->snaprd.accdb_obj_id!=ULONG_MAX );
    1932             : 
    1933           0 :   } else if( FD_UNLIKELY( !strcmp( tile->name, "snapsv" ) ) ) {
    1934             : 
    1935           0 :     tile->snapsv.snap_max      = config->firedancer.snapshots.max_full_snapshots_to_keep +
    1936           0 :                                  config->firedancer.snapshots.max_incremental_snapshots_to_keep;
    1937           0 :     tile->snapsv.conn_max      = config->firedancer.snapshots.server.max_http_connections;
    1938           0 :     tile->snapsv.io_worker_cnt = config->firedancer.layout.snapsv_io_worker_count;
    1939           0 :     tile->snapsv.idle_timeout_millis = config->firedancer.snapshots.server.idle_timeout_millis;
    1940           0 :     tile->snapsv.send_timeout_millis = config->firedancer.snapshots.server.send_timeout_millis;
    1941           0 :     tile->snapsv.send_buffer_size_kib = config->firedancer.snapshots.server.send_buffer_size_kib;
    1942             : 
    1943             :     /* An empty listen address defaults to the RPC listen address */
    1944           0 :     char const * listen_address = config->firedancer.snapshots.server.http_listen_address;
    1945           0 :     char const * listen_key     = "snapshots.server.http_listen_address";
    1946           0 :     if( FD_LIKELY( !listen_address[0] ) ) {
    1947           0 :       listen_address = config->tiles.rpc.rpc_listen_address;
    1948           0 :       listen_key     = "tiles.rpc.rpc_listen_address";
    1949           0 :     }
    1950           0 :     parse_listen_addr( listen_address, listen_key, &tile->snapsv.listen_addr );
    1951             : 
    1952           0 :     uint listen_port = config->firedancer.snapshots.server.http_listen_port;
    1953           0 :     FD_CHECK_ERR( listen_port && listen_port<=USHORT_MAX,
    1954           0 :                   "[snapshots.server.http_listen_port] must be in [1,65535]" );
    1955           0 :     tile->snapsv.listen_port = (ushort)listen_port;
    1956             : 
    1957           0 :   } else {
    1958           0 :     FD_LOG_ERR(( "unknown tile name `%s`", tile->name ));
    1959           0 :   }
    1960           0 : }

Generated by: LCOV version 1.14