Line data Source code
1 : #define _GNU_SOURCE
2 :
3 : #include "../../choreo/fd_choreo.h"
4 : #include "../../util/pod/fd_pod_format.h"
5 : #include "../../disco/keyguard/fd_keyload.h"
6 : #include "../../disco/topo/fd_topo.h"
7 : #include "../../funk/fd_funk.h"
8 : #include "../../flamenco/fd_flamenco_base.h"
9 : #include "generated/fd_tower_tile_seccomp.h"
10 :
11 0 : #define IN_KIND_GOSSIP ( 0)
12 0 : #define IN_KIND_REPLAY ( 1)
13 0 : #define IN_KIND_SHRED ( 2)
14 0 : #define IN_KIND_SIGN ( 3)
15 : #define MAX_IN_LINKS (16)
16 :
17 : #define SIGN_OUT_IDX (0)
18 :
19 : #define VOTER_MAX ( 4096UL )
20 : #define VOTER_FOOTPRINT ( 40UL ) /* serialized footprint */
21 :
22 : typedef struct {
23 : fd_wksp_t * mem;
24 : ulong chunk0;
25 : ulong wmark;
26 : ulong mtu;
27 : } in_ctx_t;
28 :
29 : typedef struct {
30 : fd_pubkey_t identity_key[1];
31 : fd_pubkey_t vote_acc[1];
32 : fd_funk_rec_key_t funk_key;
33 : ulong seed;
34 :
35 : uchar in_kind [MAX_IN_LINKS];
36 : in_ctx_t in_links[MAX_IN_LINKS];
37 :
38 : ulong replay_out_idx;
39 :
40 : ulong send_out_idx;
41 : fd_wksp_t * send_out_mem;
42 : ulong send_out_chunk0;
43 : ulong send_out_wmark;
44 : ulong send_out_chunk;
45 :
46 : fd_epoch_t * epoch;
47 : fd_ghost_t * ghost;
48 : fd_tower_t * tower;
49 :
50 : ulong root;
51 : ulong processed; /* highest processed slot (replayed & counted votes) */
52 : ulong confirmed; /* highest confirmed slot (2/3 of stake has voted) */
53 : ulong finalized; /* highest finalized slot (2/3 of stake has rooted) */
54 :
55 : fd_hash_t bank_hash; /* bank hash of the slot received from replay */
56 : fd_hash_t block_hash; /* last microblock header hash of slot received from replay */
57 : fd_hash_t slot_hash; /* hash_id of the slot received from replay (block id)*/
58 : fd_hash_t parent_hash; /* parent hash_id of the slot received from replay */
59 :
60 : fd_gossip_duplicate_shred_t duplicate_shred;
61 : uchar duplicate_shred_chunk[FD_EQVOC_PROOF_CHUNK_SZ];
62 : uchar * epoch_voters_buf;
63 : char funk_file[PATH_MAX];
64 : fd_funk_t funk[1];
65 : fd_gossip_vote_t gossip_vote;
66 : fd_lockout_offset_t lockouts[FD_TOWER_VOTE_MAX];
67 : fd_tower_t * scratch;
68 : uchar * vote_ix_buf;
69 : } ctx_t;
70 :
71 : static void
72 0 : update_epoch( ctx_t * ctx, ulong sz ) {
73 0 : fd_voter_t * epoch_voters = fd_epoch_voters( ctx->epoch );
74 0 : ctx->epoch->total_stake = 0;
75 :
76 0 : ulong off = 0;
77 0 : while( FD_LIKELY( off < sz ) ) {
78 0 : fd_pubkey_t pubkey = *(fd_pubkey_t *)fd_type_pun( ctx->epoch_voters_buf + off );
79 0 : off += sizeof(fd_pubkey_t);
80 :
81 0 : ulong stake = *(ulong *)fd_type_pun( ctx->epoch_voters_buf + off );
82 0 : off += sizeof(ulong);
83 :
84 0 : # if FD_EPOCH_USE_HANDHOLDING
85 0 : FD_TEST( !fd_epoch_voters_query( epoch_voters, pubkey, NULL ) );
86 0 : FD_TEST( fd_epoch_voters_key_cnt( epoch_voters ) < fd_epoch_voters_key_max( epoch_voters ) );
87 0 : # endif
88 :
89 0 : fd_voter_t * voter = fd_epoch_voters_insert( epoch_voters, pubkey );
90 0 : voter->rec.uc[FD_FUNK_REC_KEY_FOOTPRINT - 1] = FD_FUNK_KEY_TYPE_ACC;
91 :
92 0 : # if FD_EPOCH_USE_HANDHOLDING
93 0 : FD_TEST( 0 == memcmp( &voter->key, &pubkey, sizeof(fd_pubkey_t) ) );
94 0 : FD_TEST( fd_epoch_voters_query( epoch_voters, voter->key, NULL ) );
95 0 : # endif
96 :
97 0 : voter->stake = stake;
98 0 : voter->replay_vote.slot = FD_SLOT_NULL;
99 0 : voter->gossip_vote.slot = FD_SLOT_NULL;
100 0 : voter->rooted_vote.slot = FD_SLOT_NULL;
101 :
102 0 : ctx->epoch->total_stake += stake;
103 0 : }
104 0 : }
105 :
106 : static void
107 0 : update_ghost( ctx_t * ctx, fd_funk_txn_t * txn ) {
108 0 : fd_funk_t * funk = ctx->funk;
109 0 : fd_epoch_t * epoch = ctx->epoch;
110 0 : fd_ghost_t * ghost = ctx->ghost;
111 :
112 0 : fd_voter_t * epoch_voters = fd_epoch_voters( epoch );
113 0 : for( ulong i = 0; i < fd_epoch_voters_slot_cnt( epoch_voters ); i++ ) {
114 0 : if( FD_LIKELY( fd_epoch_voters_key_inval( epoch_voters[i].key ) ) ) continue /* most slots are empty */;
115 :
116 : /* TODO we can optimize this funk query to only check through the
117 : last slot on this fork this function was called on. currently
118 : rec_query_global traverses all the way back to the root. */
119 :
120 0 : fd_voter_t * voter = &epoch_voters[i];
121 :
122 : /* Fetch the vote account's vote slot and root slot from the vote
123 : account, re-trying if there is a Funk conflict. */
124 :
125 0 : ulong vote = FD_SLOT_NULL;
126 0 : ulong root = FD_SLOT_NULL;
127 :
128 0 : for(;;) {
129 0 : fd_funk_rec_query_t query;
130 0 : fd_funk_rec_t const * rec = fd_funk_rec_query_try_global( funk, txn, &voter->rec, NULL, &query );
131 0 : if( FD_UNLIKELY( !rec ) ) break;
132 0 : fd_voter_state_t const * state = fd_voter_state( funk, rec );
133 0 : if( FD_UNLIKELY( !state ) ) break;
134 0 : vote = fd_voter_state_vote( state );
135 0 : root = fd_voter_state_root( state );
136 0 : if( FD_LIKELY( fd_funk_rec_query_test( &query ) == FD_FUNK_SUCCESS ) ) break;
137 0 : }
138 :
139 : /* Only process votes for slots >= root. Ghost requires vote slot
140 : to already exist in the ghost tree. */
141 0 : if( FD_LIKELY( vote != FD_SLOT_NULL && vote >= fd_ghost_root( ghost )->slot ) ) {
142 : /* Check if it has crossed the equivocation safety and optimistic
143 : confirmation thresholds. */
144 :
145 0 : fd_ghost_ele_t const * ele = fd_ghost_query_const( ghost, fd_ghost_hash( ghost, vote ) );
146 :
147 : /* Error if the node's vote slot is not in ghost. This is an
148 : invariant violation, because we know their tower must be on the
149 : same fork as this current one that we're processing, and so by
150 : definition their vote slot must be in our ghost (ie. we can't
151 : have rooted past it or be on a different fork). */
152 :
153 0 : if( FD_UNLIKELY( !ele ) ) FD_LOG_ERR(( "[%s] voter %s's vote slot %lu was not in ghost", __func__, FD_BASE58_ENC_32_ALLOCA(&voter->key), vote ));
154 :
155 0 : fd_ghost_replay_vote( ghost, voter, &ele->key );
156 0 : double pct = (double)ele->replay_stake / (double)epoch->total_stake;
157 0 : if( FD_UNLIKELY( pct > FD_CONFIRMED_PCT ) ) ctx->confirmed = fd_ulong_max( ctx->confirmed, ele->slot );
158 0 : }
159 :
160 : /* Check if this voter's root >= ghost root. We can't process
161 : other voters' roots that precede the ghost root. */
162 :
163 0 : if( FD_LIKELY( root != FD_SLOT_NULL && root >= fd_ghost_root( ghost )->slot ) ) {
164 0 : fd_ghost_ele_t const * ele = fd_ghost_query( ghost, fd_ghost_hash( ghost, root ) );
165 :
166 : /* Error if the node's root slot is not in ghost. This is an
167 : invariant violation, because we know their tower must be on the
168 : same fork as this current one that we're processing, and so by
169 : definition their root slot must be in our ghost (ie. we can't
170 : have rooted past it or be on a different fork). */
171 :
172 0 : if( FD_UNLIKELY( !ele ) ) FD_LOG_ERR(( "[%s] voter %s's root slot %lu was not in ghost", __func__, FD_BASE58_ENC_32_ALLOCA(&voter->key), root ));
173 :
174 0 : fd_ghost_rooted_vote( ghost, voter, root );
175 0 : double pct = (double)ele->rooted_stake / (double)epoch->total_stake;
176 0 : if( FD_UNLIKELY( pct > FD_FINALIZED_PCT ) ) ctx->finalized = fd_ulong_max( ctx->finalized, ele->slot );
177 0 : }
178 0 : }
179 0 : }
180 :
181 :
182 : FD_FN_CONST static inline ulong
183 0 : scratch_align( void ) {
184 0 : return 128UL;
185 0 : }
186 :
187 : FD_FN_PURE static inline ulong
188 0 : scratch_footprint( fd_topo_tile_t const * tile FD_PARAM_UNUSED ) {
189 0 : return FD_LAYOUT_FINI(
190 0 : FD_LAYOUT_APPEND(
191 0 : FD_LAYOUT_APPEND(
192 0 : FD_LAYOUT_APPEND(
193 0 : FD_LAYOUT_APPEND(
194 0 : FD_LAYOUT_APPEND(
195 0 : FD_LAYOUT_APPEND(
196 0 : FD_LAYOUT_INIT,
197 0 : alignof(ctx_t), sizeof(ctx_t) ),
198 0 : fd_epoch_align(), fd_epoch_footprint( FD_VOTER_MAX ) ),
199 0 : fd_ghost_align(), fd_ghost_footprint( FD_BLOCK_MAX ) ),
200 0 : fd_tower_align(), fd_tower_footprint() ), /* our tower */
201 0 : fd_tower_align(), fd_tower_footprint() ), /* scratch */
202 0 : 128UL, VOTER_FOOTPRINT * VOTER_MAX ), /* scratch */
203 0 : scratch_align() );
204 0 : }
205 :
206 : static void
207 : during_frag( ctx_t * ctx,
208 : ulong in_idx,
209 : ulong seq FD_PARAM_UNUSED,
210 : ulong sig,
211 : ulong chunk,
212 : ulong sz,
213 0 : ulong ctl FD_PARAM_UNUSED ) {
214 0 : uint in_kind = ctx->in_kind[in_idx];
215 0 : in_ctx_t const * in_ctx = &ctx->in_links[in_idx];
216 0 : switch( in_kind ) {
217 :
218 0 : case IN_KIND_GOSSIP: {
219 0 : uchar const * chunk_laddr = fd_chunk_to_laddr_const( in_ctx->mem, chunk );
220 0 : switch(sig) {
221 0 : case fd_crds_data_enum_vote: {
222 0 : memcpy( &ctx->vote_ix_buf[0], chunk_laddr, sz );
223 0 : break;
224 0 : }
225 0 : case fd_crds_data_enum_duplicate_shred: {
226 0 : memcpy( &ctx->duplicate_shred, chunk_laddr, sizeof(fd_gossip_duplicate_shred_t) );
227 0 : memcpy( ctx->duplicate_shred_chunk, chunk_laddr + sizeof(fd_gossip_duplicate_shred_t), FD_EQVOC_PROOF_CHUNK_SZ );
228 0 : break;
229 0 : }
230 0 : default: {
231 0 : FD_LOG_ERR(( "unexpected crds discriminant %lu", sig ));
232 0 : break;
233 0 : }
234 0 : }
235 0 : break;
236 0 : }
237 :
238 0 : case IN_KIND_REPLAY: {
239 0 : in_ctx_t const * in_ctx = &ctx->in_links[ in_idx ];
240 0 : ulong parent_slot = fd_ulong_extract_lsb( sig, 32 );
241 0 : uchar const * chunk_laddr = fd_chunk_to_laddr_const( in_ctx->mem, chunk );
242 0 : if( FD_UNLIKELY( parent_slot == UINT_MAX /* no parent, so snapshot slot */ ) ) {
243 0 : memcpy ( ctx->slot_hash.uc, chunk_laddr, sizeof(fd_hash_t) );
244 0 : fd_memcpy( ctx->epoch_voters_buf, chunk_laddr + sizeof(fd_hash_t), sz - sizeof(fd_hash_t) );
245 0 : } else {
246 0 : memcpy( ctx->bank_hash.uc, chunk_laddr, sizeof(fd_hash_t) );
247 0 : memcpy( ctx->block_hash.uc, chunk_laddr+1*sizeof(fd_hash_t), sizeof(fd_hash_t) );
248 0 : memcpy( ctx->slot_hash.uc, chunk_laddr+2*sizeof(fd_hash_t), sizeof(fd_hash_t) );
249 0 : memcpy( ctx->parent_hash.uc, chunk_laddr+3*sizeof(fd_hash_t), sizeof(fd_hash_t) );
250 : /* FIXME: worth making a repair->replay packed msg to directly cast? */
251 0 : }
252 0 : break;
253 0 : }
254 :
255 0 : case IN_KIND_SHRED:
256 0 : break;
257 :
258 0 : case IN_KIND_SIGN:
259 0 : break;
260 :
261 0 : default:
262 0 : FD_LOG_ERR(( "Unknown in_kind %u", in_kind ));
263 0 : }
264 0 : }
265 :
266 : static void
267 : after_frag( ctx_t * ctx,
268 : ulong in_idx,
269 : ulong seq FD_PARAM_UNUSED,
270 : ulong sig,
271 : ulong sz,
272 : ulong tsorig,
273 : ulong tspub FD_PARAM_UNUSED,
274 0 : fd_stem_context_t * stem ) {
275 0 : uint in_kind = ctx->in_kind[in_idx];
276 0 : if( FD_UNLIKELY( in_kind != IN_KIND_REPLAY ) ) return;
277 :
278 0 : ulong slot = fd_ulong_extract( sig, 32, 63 );
279 0 : ulong parent_slot = fd_ulong_extract_lsb( sig, 32 );
280 :
281 0 : if( FD_UNLIKELY( (uint)parent_slot == UINT_MAX ) ) { /* snapshot slot */
282 0 : FD_TEST( ctx->funk );
283 0 : FD_TEST( fd_funk_txn_map( ctx->funk ) );
284 0 : update_epoch( ctx, sz - sizeof(fd_hash_t) );
285 0 : fd_ghost_init( ctx->ghost, slot, &ctx->slot_hash );
286 0 : return;
287 0 : }
288 :
289 0 : fd_funk_txn_xid_t txn_xid = { .ul = { slot, slot } };
290 0 : fd_funk_txn_map_t * txn_map = fd_funk_txn_map( ctx->funk );
291 0 : fd_funk_txn_start_read( ctx->funk );
292 0 : fd_funk_txn_t * funk_txn = fd_funk_txn_query( &txn_xid, txn_map );
293 0 : if( FD_UNLIKELY( !funk_txn ) ) FD_LOG_ERR(( "Could not find valid funk transaction" ));
294 0 : fd_funk_txn_end_read( ctx->funk );
295 :
296 : /* Initialize the tower */
297 :
298 0 : if( FD_UNLIKELY( fd_tower_votes_empty( ctx->tower ) ) ) fd_tower_from_vote_acc( ctx->tower, ctx->funk, funk_txn, &ctx->funk_key );
299 :
300 0 : fd_ghost_ele_t const * ghost_ele = fd_ghost_insert( ctx->ghost, &ctx->parent_hash, slot, &ctx->slot_hash, ctx->epoch->total_stake );
301 0 : FD_TEST( ghost_ele );
302 0 : update_ghost( ctx, funk_txn );
303 :
304 0 : ulong vote_slot = fd_tower_vote_slot( ctx->tower, ctx->epoch, ctx->funk, funk_txn, ctx->ghost, ctx->scratch );
305 0 : if( FD_UNLIKELY( vote_slot == FD_SLOT_NULL ) ) return; /* nothing to vote on */
306 :
307 0 : ulong root = fd_tower_vote( ctx->tower, vote_slot );
308 0 : if( FD_LIKELY( root != FD_SLOT_NULL ) ) {
309 0 : fd_hash_t const * root_bid = fd_ghost_hash( ctx->ghost, root );
310 0 : if( FD_UNLIKELY( !root_bid ) ) {
311 0 : FD_LOG_WARNING(( "Lowest vote slot %lu is not in ghost, skipping publish", root ));
312 0 : } else {
313 0 : fd_ghost_publish( ctx->ghost, root_bid );
314 0 : fd_stem_publish( stem, ctx->replay_out_idx, root, 0UL, 0UL, 0UL, tsorig, fd_frag_meta_ts_comp( fd_tickcount() ) );
315 0 : }
316 0 : ctx->root = root;
317 0 : }
318 :
319 : /* Send our updated tower to the cluster. */
320 :
321 0 : fd_txn_p_t * vote_txn = (fd_txn_p_t *)fd_chunk_to_laddr( ctx->send_out_mem, ctx->send_out_chunk );
322 0 : fd_tower_to_vote_txn( ctx->tower, ctx->root, ctx->lockouts, &ctx->bank_hash, &ctx->block_hash, ctx->identity_key, ctx->identity_key, ctx->vote_acc, vote_txn );
323 0 : FD_TEST( !fd_tower_votes_empty( ctx->tower ) );
324 0 : FD_TEST( vote_txn->payload_sz > 0UL );
325 0 : fd_stem_publish( stem, ctx->send_out_idx, vote_slot, ctx->send_out_chunk, sizeof(fd_txn_p_t), 0UL, tsorig, fd_frag_meta_ts_comp( fd_tickcount() ) );
326 :
327 0 : fd_ghost_print( ctx->ghost, ctx->epoch->total_stake, fd_ghost_root( ctx->ghost ) );
328 0 : fd_tower_print( ctx->tower, ctx->root );
329 0 : }
330 :
331 : static void
332 : unprivileged_init( fd_topo_t * topo,
333 0 : fd_topo_tile_t * tile ) {
334 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
335 :
336 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
337 0 : ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof(ctx_t), sizeof(ctx_t) );
338 0 : void * epoch_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_align(), fd_epoch_footprint( FD_VOTER_MAX ) );
339 0 : void * ghost_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_ghost_align(), fd_ghost_footprint( FD_BLOCK_MAX ) );
340 0 : void * tower_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_tower_align(), fd_tower_footprint() );
341 0 : void * scratch_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_tower_align(), fd_tower_footprint() );
342 0 : void * voter_mem = FD_SCRATCH_ALLOC_APPEND( l, 128UL, VOTER_FOOTPRINT * VOTER_MAX );
343 0 : ulong scratch_top = FD_SCRATCH_ALLOC_FINI ( l, scratch_align() );
344 0 : FD_TEST( scratch_top == (ulong)scratch + scratch_footprint( tile ) );
345 :
346 0 : ctx->epoch = fd_epoch_join( fd_epoch_new( epoch_mem, FD_VOTER_MAX ) );
347 0 : ctx->ghost = fd_ghost_join( fd_ghost_new( ghost_mem, FD_BLOCK_MAX, 42UL ) );
348 0 : ctx->tower = fd_tower_join( fd_tower_new( tower_mem ) );
349 0 : ctx->scratch = fd_tower_join( fd_tower_new( scratch_mem ) );
350 :
351 0 : if( FD_UNLIKELY( !fd_funk_join( ctx->funk, fd_topo_obj_laddr( topo, tile->tower.funk_obj_id ) ) ) ) {
352 0 : FD_LOG_ERR(( "Failed to join database cache" ));
353 0 : }
354 :
355 0 : ctx->epoch_voters_buf = voter_mem;
356 :
357 0 : memcpy( ctx->identity_key->uc, fd_keyload_load( tile->tower.identity_key_path, 1 ), sizeof(fd_pubkey_t) );
358 :
359 0 : if( FD_UNLIKELY( !fd_base58_decode_32( tile->tower.vote_acc_path, ctx->vote_acc->uc ) ) ) {
360 0 : const uchar * vote_key = fd_keyload_load( tile->tower.vote_acc_path, 1 );
361 0 : memcpy( ctx->vote_acc->uc, vote_key, sizeof(fd_pubkey_t) );
362 0 : }
363 :
364 0 : memset( ctx->funk_key.uc, 0, sizeof(fd_funk_rec_key_t) );
365 0 : memcpy( ctx->funk_key.uc, ctx->vote_acc->uc, sizeof(fd_pubkey_t) );
366 0 : ctx->funk_key.uc[FD_FUNK_REC_KEY_FOOTPRINT - 1] = FD_FUNK_KEY_TYPE_ACC;
367 :
368 0 : if( FD_UNLIKELY( tile->in_cnt > MAX_IN_LINKS ) ) FD_LOG_ERR(( "repair tile has too many input links" ));
369 :
370 0 : for( uint in_idx=0U; in_idx<(tile->in_cnt); in_idx++ ) {
371 0 : fd_topo_link_t * link = &topo->links[ tile->in_link_id[ in_idx ] ];
372 0 : if( 0==strcmp( link->name, "gossip_tower" ) ) {
373 0 : ctx->in_kind[ in_idx ] = IN_KIND_GOSSIP;
374 0 : } else if( 0==strcmp( link->name, "replay_tower" ) ) {
375 0 : ctx->in_kind[ in_idx ] = IN_KIND_REPLAY;
376 0 : } else if( 0==strcmp( link->name, "stake_out" ) ) {
377 0 : ctx->in_kind[ in_idx ] = IN_KIND_SHRED;
378 0 : } else {
379 0 : FD_LOG_ERR(( "tower tile has unexpected input link %s", link->name ));
380 0 : }
381 0 : ctx->in_links[ in_idx ].mem = topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ].wksp;
382 0 : ctx->in_links[ in_idx ].chunk0 = fd_dcache_compact_chunk0( ctx->in_links[ in_idx ].mem, link->dcache );
383 0 : ctx->in_links[ in_idx ].wmark = fd_dcache_compact_wmark ( ctx->in_links[ in_idx ].mem, link->dcache, link->mtu );
384 0 : ctx->in_links[ in_idx ].mtu = link->mtu;
385 0 : }
386 :
387 0 : ctx->replay_out_idx = fd_topo_find_tile_out_link( topo, tile, "tower_replay", 0 );
388 0 : FD_TEST( ctx->replay_out_idx!= ULONG_MAX );
389 :
390 0 : ctx->send_out_idx = fd_topo_find_tile_out_link( topo, tile, "tower_send", 0 );
391 0 : FD_TEST( ctx->send_out_idx!=ULONG_MAX );
392 0 : fd_topo_link_t * send_out = &topo->links[ tile->out_link_id[ ctx->send_out_idx ] ];
393 0 : ctx->send_out_mem = topo->workspaces[ topo->objs[ send_out->dcache_obj_id ].wksp_id ].wksp;
394 0 : ctx->send_out_chunk0 = fd_dcache_compact_chunk0( ctx->send_out_mem, send_out->dcache );
395 0 : ctx->send_out_wmark = fd_dcache_compact_wmark ( ctx->send_out_mem, send_out->dcache, send_out->mtu );
396 0 : ctx->send_out_chunk = ctx->send_out_chunk0;
397 0 : FD_TEST( fd_dcache_compact_is_safe( ctx->send_out_mem, send_out->dcache, send_out->mtu, send_out->depth ) );
398 0 : }
399 :
400 : static ulong
401 : populate_allowed_seccomp( fd_topo_t const * topo,
402 : fd_topo_tile_t const * tile,
403 : ulong out_cnt,
404 0 : struct sock_filter * out ) {
405 0 : (void)topo;
406 0 : (void)tile;
407 :
408 0 : populate_sock_filter_policy_fd_tower_tile( out_cnt, out, (uint)fd_log_private_logfile_fd() );
409 0 : return sock_filter_policy_fd_tower_tile_instr_cnt;
410 0 : }
411 :
412 : static ulong
413 : populate_allowed_fds( fd_topo_t const * topo,
414 : fd_topo_tile_t const * tile,
415 : ulong out_fds_cnt,
416 0 : int * out_fds ) {
417 0 : (void)topo;
418 0 : (void)tile;
419 :
420 0 : if( FD_UNLIKELY( out_fds_cnt<2UL ) ) FD_LOG_ERR(( "out_fds_cnt %lu", out_fds_cnt ));
421 :
422 0 : ulong out_cnt = 0UL;
423 0 : out_fds[ out_cnt++ ] = 2; /* stderr */
424 0 : if( FD_LIKELY( -1!=fd_log_private_logfile_fd() ) )
425 0 : out_fds[ out_cnt++ ] = fd_log_private_logfile_fd(); /* logfile */
426 0 : return out_cnt;
427 0 : }
428 :
429 0 : #define STEM_BURST (1UL)
430 :
431 0 : #define STEM_CALLBACK_CONTEXT_TYPE ctx_t
432 0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(ctx_t)
433 0 : #define STEM_CALLBACK_DURING_FRAG during_frag
434 0 : #define STEM_CALLBACK_AFTER_FRAG after_frag
435 :
436 : #include "../../disco/stem/fd_stem.c"
437 :
438 : fd_topo_run_tile_t fd_tile_tower = {
439 : .name = "tower",
440 : .populate_allowed_seccomp = populate_allowed_seccomp,
441 : .populate_allowed_fds = populate_allowed_fds,
442 : .scratch_align = scratch_align,
443 : .scratch_footprint = scratch_footprint,
444 : .unprivileged_init = unprivileged_init,
445 : .run = stem_run,
446 : };
|