Line data Source code
1 : #include "fd_poh.h"
2 :
3 : #include "../../disco/pack/fd_pack.h"
4 : #include "../../ballet/sha256/fd_sha256.h"
5 : #include "../../disco/topo/fd_pod_format.h"
6 : #include "../../disco/shred/fd_shredder.h"
7 : #include "../../disco/shred/fd_stake_ci.h"
8 : #include "../../disco/keyguard/fd_keyload.h"
9 : #include "../../disco/metrics/generated/fd_metrics_poh.h"
10 : #include "../../flamenco/leaders/fd_leaders.h"
11 : #include "../../flamenco/fd_flamenco.h"
12 :
13 : /* TODO: TILE NEEDS SECCOMP POLICY */
14 :
15 : /* The PoH recorder is implemented in Firedancer but for now needs to
16 : work with Agave, so we have a locking scheme for them to
17 : co-operate.
18 :
19 : This is because the PoH tile lives in the Agave memory address
20 : space and their version of concurrency is locking the PoH recorder
21 : and reading arbitrary fields.
22 :
23 : So we allow them to lock the PoH tile, although with a very bad (for
24 : them) locking scheme. By default, the tile has full and exclusive
25 : access to the data. If part of Agave wishes to read/write they
26 : can either,
27 :
28 : 1. Rewrite their concurrency to message passing based on mcache
29 : (preferred, but not feasible).
30 : 2. Signal to the tile they wish to acquire the lock, by setting
31 : fd_poh_waiting_lock to 1.
32 :
33 : During housekeeping, the tile will check if there is the waiting lock
34 : is set to 1, and if so, set the returned lock to 1, indicating to the
35 : waiter that they may now proceed.
36 :
37 : When the waiter is done reading and writing, they restore the
38 : returned lock value back to zero, and the POH tile continues with its
39 : day. */
40 :
41 : typedef struct {
42 : fd_poh_tile_ctx_t * poh_tile_ctx;
43 :
44 : int filter_frag;
45 :
46 : ulong bank_cnt;
47 : ulong * bank_busy[ 64UL ];
48 :
49 : ulong stake_in_idx;
50 :
51 : ulong pack_in_idx;
52 :
53 : /* These are temporarily set in during_frag so they can be used in
54 : after_frag once the frag has been validated as not overrun. */
55 : uchar _txns[ 1024* USHORT_MAX ];
56 : fd_microblock_trailer_t _microblock_trailer[1];
57 :
58 : int is_initialized;
59 : int recently_reset;
60 :
61 : ulong * current_slot;
62 :
63 : fd_poh_tile_in_ctx_t bank_in[ 32 ];
64 : fd_poh_tile_in_ctx_t stake_in;
65 : fd_poh_tile_in_ctx_t pack_in;
66 :
67 : fd_wksp_t * shred_out_mem;
68 : ulong shred_out_chunk0;
69 : ulong shred_out_wmark;
70 : ulong shred_out_chunk;
71 :
72 : fd_frag_meta_t * pack_out_mcache;
73 : ulong pack_out_depth;
74 : ulong pack_out_seq;
75 : ulong * pack_out_sync;
76 :
77 : fd_wksp_t * pack_out_mem;
78 : ulong pack_out_chunk0;
79 : ulong pack_out_wmark;
80 : ulong pack_out_chunk;
81 :
82 : fd_stem_context_t * stem;
83 :
84 : } fd_poh_ctx_t;
85 :
86 : static void
87 0 : signal_leader_change( void * _arg FD_PARAM_UNUSED ) {
88 : // TODO publishing etc
89 0 : }
90 :
91 : static void *
92 0 : get_mircoblock_buffer( void * _arg ) {
93 0 : fd_poh_ctx_t * ctx = (fd_poh_ctx_t *)_arg;
94 0 : uchar * dst = (uchar *)fd_chunk_to_laddr( ctx->shred_out_mem, ctx->shred_out_chunk );
95 0 : return dst;
96 0 : }
97 :
98 : static void
99 0 : publish_microblock( void * _arg, ulong tspub, ulong sig, ulong sz ) {
100 0 : fd_poh_ctx_t * ctx = (fd_poh_ctx_t *)_arg;
101 0 : fd_stem_publish( ctx->stem, 0UL, sig, ctx->shred_out_chunk, sz, 0UL, 0UL, tspub );
102 0 : ctx->shred_out_chunk = fd_dcache_compact_next( ctx->shred_out_chunk, sz, ctx->shred_out_chunk0, ctx->shred_out_wmark );
103 0 : }
104 :
105 : static void *
106 0 : get_pack_buffer( void * _arg ) {
107 0 : fd_poh_ctx_t * ctx = (fd_poh_ctx_t *)_arg;
108 0 : uchar * dst = (uchar *)fd_chunk_to_laddr( ctx->pack_out_mem, ctx->pack_out_chunk );
109 0 : return dst;
110 0 : }
111 :
112 : static void
113 0 : publish_pack( void * _arg, ulong tspub, ulong sig, ulong sz ) {
114 0 : fd_poh_ctx_t * ctx = (fd_poh_ctx_t *)_arg;
115 0 : fd_mcache_publish( ctx->pack_out_mcache, ctx->pack_out_depth, ctx->pack_out_seq, sig, ctx->pack_out_chunk, sizeof(fd_became_leader_t), 0UL, 0UL, tspub );
116 0 : ctx->pack_out_chunk = fd_dcache_compact_next( ctx->pack_out_chunk, sz, ctx->pack_out_chunk0, ctx->pack_out_wmark );
117 0 : ctx->pack_out_seq = fd_seq_inc( ctx->pack_out_seq, 1UL );
118 0 : }
119 :
120 : static void
121 : register_tick( void * _arg FD_PARAM_UNUSED,
122 : ulong current_leader_slot FD_PARAM_UNUSED,
123 0 : uchar hash[ static 32 ] FD_PARAM_UNUSED ) { }
124 :
125 : /* The PoH tile needs to interact with the Agave address space to
126 : do certain operations that Firedancer hasn't reimplemented yet, a.k.a
127 : transaction execution. We have Agave export some wrapper
128 : functions that we call into during regular tile execution. These do
129 : not need any locking, since they are called serially from the single
130 : PoH tile. */
131 :
132 : extern void fd_ext_bank_acquire( void const * bank );
133 : extern void fd_ext_bank_release( void const * bank );
134 :
135 0 : void fd_poh_signal_leader_change( fd_poh_ctx_t * ctx FD_PARAM_UNUSED ) { }
136 :
137 : void fd_poh_register_tick( fd_poh_ctx_t * ctx FD_PARAM_UNUSED,
138 : ulong reset_slot FD_PARAM_UNUSED,
139 0 : uchar const * hash FD_PARAM_UNUSED ) { }
140 :
141 : /* fd_ext_poh_initialize is called by Agave on startup to
142 : initialize the PoH tile with some static configuration, and the
143 : initial reset slot and hash which it retrieves from a snapshot.
144 :
145 : This function is called by some random Agave thread, but
146 : it blocks booting of the PoH tile. The tile will spin until it
147 : determines that this initialization has happened.
148 :
149 : signal_leader_change is an opaque Rust object that is used to
150 : tell the replay stage that the leader has changed. It is a
151 : Box::into_raw(Arc::increment_strong(crossbeam::Sender)), so it
152 : has infinite lifetime unless this C code releases the refcnt.
153 :
154 : It can be used with `fd_ext_poh_signal_leader_change` which
155 : will just issue a nonblocking send on the channel. */
156 :
157 : void
158 : fd_poh_initialize( fd_poh_ctx_t * ctx,
159 : ulong tick_duration_ns, /* See clock comments above, will be 500ns for mainnet-beta. */
160 : ulong hashcnt_per_tick, /* See clock comments above, will be 12,500 for mainnet-beta. */
161 : ulong ticks_per_slot, /* See clock comments above, will almost always be 64. */
162 : ulong tick_height, /* The counter (height) of the tick to start hashing on top of. */
163 0 : uchar const * last_entry_hash /* Points to start of a 32 byte region of memory, the hash itself at the tick height. */ ) {
164 0 : fd_poh_tile_initialize( ctx->poh_tile_ctx, tick_duration_ns, hashcnt_per_tick, ticks_per_slot, tick_height,
165 0 : last_entry_hash );
166 0 : ctx->recently_reset = 1;
167 0 : ctx->is_initialized = 1;
168 0 : }
169 :
170 : /* fd_ext_poh_reset is called by the Agave client when a slot on
171 : the active fork has finished a block and we need to reset our PoH to
172 : be ticking on top of the block it produced. */
173 :
174 : FD_FN_CONST static inline ulong
175 0 : scratch_align( void ) {
176 0 : return 128UL;
177 0 : }
178 :
179 : FD_FN_PURE static inline ulong
180 0 : scratch_footprint( fd_topo_tile_t const * tile ) {
181 0 : (void)tile;
182 0 : ulong l = FD_LAYOUT_INIT;
183 0 : l = FD_LAYOUT_APPEND( l, alignof( fd_poh_ctx_t ), sizeof( fd_poh_ctx_t ) );
184 0 : l = FD_LAYOUT_APPEND( l, fd_poh_tile_align(), fd_poh_tile_footprint() );
185 0 : return FD_LAYOUT_FINI( l, scratch_align() );
186 0 : }
187 :
188 : static inline void
189 : after_credit( fd_poh_ctx_t * ctx,
190 : fd_stem_context_t * stem,
191 : int * opt_poll_in,
192 0 : int * charge_busy ) {
193 0 : ctx->stem = stem;
194 :
195 0 : if( FD_UNLIKELY( !ctx->is_initialized ) ) return;
196 :
197 0 : if( FD_LIKELY( ctx->poh_tile_ctx->current_leader_slot==FD_SLOT_NULL && ctx->recently_reset ) ) {
198 : /* We are not leader, but we should check if we have reached a leader slot! */
199 0 : ulong leader_slot = FD_SLOT_NULL;
200 0 : ulong reset_slot = FD_SLOT_NULL;
201 0 : int has_reached_leader_slot = fd_poh_tile_reached_leader_slot( ctx->poh_tile_ctx, &leader_slot, &reset_slot );
202 0 : if( has_reached_leader_slot ) {
203 0 : fd_poh_tile_begin_leader( ctx->poh_tile_ctx, leader_slot, ctx->poh_tile_ctx->hashcnt_per_tick );
204 0 : ctx->recently_reset = 0;
205 0 : }
206 0 : *charge_busy = 1;
207 0 : }
208 :
209 0 : if( FD_LIKELY( fd_poh_tile_after_credit( ctx->poh_tile_ctx, opt_poll_in ) ) ) {
210 0 : *charge_busy = 1;
211 0 : }
212 :
213 0 : fd_fseq_update( ctx->current_slot, ctx->poh_tile_ctx->slot );
214 0 : }
215 :
216 : static inline void
217 0 : during_housekeeping( fd_poh_ctx_t * ctx ) {
218 0 : fd_poh_tile_during_housekeeping( ctx->poh_tile_ctx );
219 0 : }
220 :
221 : static inline void
222 : during_frag( fd_poh_ctx_t * ctx,
223 : ulong in_idx,
224 : ulong seq FD_PARAM_UNUSED,
225 : ulong sig,
226 : ulong chunk,
227 : ulong sz,
228 0 : ulong ctl FD_PARAM_UNUSED ) {
229 :
230 0 : ctx->filter_frag = 0;
231 :
232 0 : if( FD_UNLIKELY( in_idx==ctx->stake_in_idx ) ) {
233 0 : if( FD_UNLIKELY( chunk<ctx->stake_in.chunk0 || chunk>ctx->stake_in.wmark ) )
234 0 : FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]", chunk, sz,
235 0 : ctx->stake_in.chunk0, ctx->stake_in.wmark ));
236 :
237 0 : uchar const * dcache_entry = fd_chunk_to_laddr_const( ctx->stake_in.mem, chunk );
238 0 : fd_poh_tile_init_stakes( ctx->poh_tile_ctx, dcache_entry );
239 0 : return;
240 0 : }
241 :
242 0 : ulong pkt_type;
243 0 : ulong slot;
244 0 : if( FD_UNLIKELY( in_idx==ctx->pack_in_idx ) ) {
245 0 : pkt_type = fd_disco_poh_sig_pkt_type( sig );
246 0 : slot = fd_disco_poh_sig_slot( sig );
247 0 : } else {
248 0 : pkt_type = POH_PKT_TYPE_MICROBLOCK;
249 0 : slot = fd_disco_bank_sig_slot( sig );
250 0 : }
251 :
252 0 : int is_frag_for_prior_leader_slot = 0;
253 0 : if( FD_LIKELY( pkt_type==POH_PKT_TYPE_DONE_PACKING || pkt_type==POH_PKT_TYPE_MICROBLOCK ) ) {
254 : /* The following sequence is possible...
255 :
256 : 1. We become leader in slot 10
257 : 2. While leader, we switch to a fork that is on slot 8, where
258 : we are leader
259 : 3. We get the in-flight microblocks for slot 10
260 :
261 : These in-flight microblocks need to be dropped, so we check
262 : against the high water mark (highwater_leader_slot) rather than
263 : the current hashcnt here when determining what to drop.
264 :
265 : We know if the slot is lower than the high water mark it's from a stale
266 : leader slot, because we will not become leader for the same slot twice
267 : even if we are reset back in time (to prevent duplicate blocks). */
268 0 : is_frag_for_prior_leader_slot = slot<ctx->poh_tile_ctx->highwater_leader_slot;
269 0 : }
270 :
271 0 : if( FD_UNLIKELY( in_idx==ctx->pack_in_idx ) ) {
272 : /* We now know the real amount of microblocks published, so set an
273 : exact bound for once we receive them. */
274 0 : ctx->filter_frag = 1;
275 0 : if( fd_disco_poh_sig_pkt_type( sig )==POH_PKT_TYPE_DONE_PACKING ) {
276 0 : if( FD_UNLIKELY( is_frag_for_prior_leader_slot ) ) return;
277 :
278 0 : fd_done_packing_t const * done_packing = fd_chunk_to_laddr( ctx->pack_in.mem, chunk );
279 0 : fd_poh_tile_done_packing( ctx->poh_tile_ctx, done_packing->microblocks_in_slot );
280 0 : }
281 0 : return;
282 0 : } else {
283 0 : if( FD_UNLIKELY( chunk<ctx->bank_in[ in_idx ].chunk0 || chunk>ctx->bank_in[ in_idx ].wmark || sz>USHORT_MAX ) )
284 0 : FD_LOG_ERR(( "chunk %lu %lu corrupt, not in range [%lu,%lu]", chunk, sz, ctx->bank_in[ in_idx ].chunk0, ctx->bank_in[ in_idx ].wmark ));
285 :
286 0 : if( !ctx->is_initialized && fd_disco_replay_old_sig_flags( sig )==REPLAY_FLAG_INIT ) {
287 0 : FD_LOG_INFO(( "init msg rx" ));
288 0 : fd_poh_init_msg_t * init_msg = (fd_poh_init_msg_t *)fd_chunk_to_laddr( ctx->bank_in[ in_idx ].mem, chunk );
289 0 : fd_poh_initialize( ctx, init_msg->tick_duration_ns, init_msg->hashcnt_per_tick, init_msg->ticks_per_slot, init_msg->tick_height, init_msg->last_entry_hash );
290 0 : ctx->filter_frag = 1;
291 0 : return;
292 0 : }
293 0 : uchar * src = (uchar *)fd_chunk_to_laddr( ctx->bank_in[ in_idx ].mem, chunk );
294 :
295 0 : ulong raw_sz = (sz * sizeof(fd_txn_p_t))+sizeof(fd_microblock_trailer_t);
296 0 : FD_TEST( raw_sz<=1024*USHORT_MAX );
297 0 : fd_memcpy( ctx->_txns, src, raw_sz-sizeof(fd_microblock_trailer_t) );
298 0 : fd_memcpy( ctx->_microblock_trailer, src+(sz * sizeof(fd_txn_p_t)), sizeof(fd_microblock_trailer_t) );
299 :
300 0 : ctx->filter_frag = is_frag_for_prior_leader_slot;
301 0 : }
302 0 : }
303 :
304 : static inline void
305 : after_frag( fd_poh_ctx_t * ctx,
306 : ulong in_idx,
307 : ulong seq,
308 : ulong sig,
309 : ulong sz,
310 : ulong tsorig,
311 : ulong tspub,
312 0 : fd_stem_context_t * stem ) {
313 0 : (void)seq;
314 0 : (void)tsorig;
315 0 : (void)tspub;
316 0 : (void)stem;
317 :
318 0 : if( FD_UNLIKELY( ctx->filter_frag ) ) return;
319 :
320 0 : if( FD_UNLIKELY( in_idx==ctx->stake_in_idx ) ) {
321 : /* Nothing to do if we transition into being leader, since it
322 : will just get picked up by the regular tick loop. */
323 0 : fd_poh_tile_fini_stakes( ctx->poh_tile_ctx );
324 0 : return;
325 0 : }
326 :
327 0 : if( FD_UNLIKELY( !ctx->poh_tile_ctx->microblocks_lower_bound ) ) {
328 0 : double tick_per_ns = fd_tempo_tick_per_ns( NULL );
329 0 : fd_histf_sample( ctx->poh_tile_ctx->first_microblock_delay, (ulong)((double)(fd_log_wallclock()-ctx->poh_tile_ctx->reset_slot_start_ns)/tick_per_ns) );
330 0 : }
331 :
332 0 : ulong target_flags = fd_disco_replay_old_sig_flags( sig );
333 0 : ulong target_slot = fd_disco_replay_old_sig_slot( sig );
334 :
335 0 : ulong is_packed_microblock = target_flags & REPLAY_FLAG_PACKED_MICROBLOCK;
336 0 : ulong is_finalized_block = target_flags & REPLAY_FLAG_FINISHED_BLOCK;
337 : // ulong is_catching_up = target_flags & REPLAY_FLAG_CATCHING_UP;
338 :
339 0 : if( is_packed_microblock ) {
340 0 : ulong txn_cnt = sz;
341 0 : fd_txn_p_t * txns = (fd_txn_p_t *)(ctx->_txns);
342 0 : ulong sig = fd_disco_poh_sig( target_slot, POH_PKT_TYPE_MICROBLOCK, in_idx );
343 0 : fd_poh_tile_process_packed_microblock( ctx->poh_tile_ctx, target_slot, sig, txns, txn_cnt, ctx->_microblock_trailer->hash );
344 0 : } else {
345 0 : if( is_finalized_block && ctx->is_initialized ) {
346 0 : fd_poh_tile_reset( ctx->poh_tile_ctx, target_slot, ctx->_microblock_trailer->hash, ctx->poh_tile_ctx->hashcnt_per_tick );
347 0 : ctx->recently_reset = 1;
348 0 : }
349 0 : }
350 0 : }
351 :
352 : static void
353 : privileged_init( fd_topo_t * topo,
354 0 : fd_topo_tile_t * tile ) {
355 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
356 :
357 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
358 0 : fd_poh_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_poh_ctx_t ), sizeof( fd_poh_ctx_t ) );
359 0 : ctx->poh_tile_ctx = FD_SCRATCH_ALLOC_APPEND( l, fd_poh_tile_align(), fd_poh_tile_footprint() );
360 :
361 0 : if( FD_UNLIKELY( !strcmp( tile->poh.identity_key_path, "" ) ) )
362 0 : FD_LOG_ERR(( "identity_key_path not set" ));
363 :
364 0 : const uchar * identity_key = fd_keyload_load( tile->poh.identity_key_path, /* pubkey only: */ 1 );
365 0 : fd_memcpy( ctx->poh_tile_ctx->identity_key.uc, identity_key, 32UL );
366 0 : }
367 :
368 : static void
369 : unprivileged_init( fd_topo_t * topo,
370 0 : fd_topo_tile_t * tile ) {
371 0 : void * scratch = fd_topo_obj_laddr( topo, tile->tile_obj_id );
372 :
373 0 : FD_SCRATCH_ALLOC_INIT( l, scratch );
374 0 : fd_poh_ctx_t * ctx = FD_SCRATCH_ALLOC_APPEND( l, alignof( fd_poh_ctx_t ), sizeof( fd_poh_ctx_t ) );
375 0 : ctx->poh_tile_ctx = FD_SCRATCH_ALLOC_APPEND( l, fd_poh_tile_align(), fd_poh_tile_footprint() );
376 0 : #define NONNULL( x ) (__extension__({ \
377 0 : __typeof__((x)) __x = (x); \
378 0 : if( FD_UNLIKELY( !__x ) ) FD_LOG_ERR(( #x " was unexpectedly NULL" )); \
379 0 : __x; }))
380 :
381 : // TODO: scratch alloc needs fixing!
382 0 : fd_poh_tile_new( ctx->poh_tile_ctx, ctx, get_mircoblock_buffer, publish_microblock, get_pack_buffer, publish_pack, register_tick, signal_leader_change );
383 :
384 0 : ulong poh_slot_obj_id = fd_pod_query_ulong( topo->props, "poh_slot", ULONG_MAX );
385 0 : FD_TEST( poh_slot_obj_id!=ULONG_MAX );
386 0 : ctx->current_slot = fd_fseq_join( fd_topo_obj_laddr( topo, poh_slot_obj_id ) );
387 :
388 0 : ctx->is_initialized = 0;
389 0 : ctx->recently_reset = 0;
390 0 : ctx->bank_cnt = tile->in_cnt-2UL;
391 0 : ctx->stake_in_idx = tile->in_cnt-2UL;
392 0 : ctx->pack_in_idx = tile->in_cnt-1UL;
393 :
394 0 : FD_TEST( ctx->bank_cnt<=sizeof(ctx->bank_busy)/sizeof(ctx->bank_busy[0]) );
395 0 : for( ulong i=0UL; i<ctx->bank_cnt; i++ ) {
396 0 : ulong busy_obj_id = fd_pod_queryf_ulong( topo->props, ULONG_MAX, "bank_busy.%lu", i );
397 0 : FD_TEST( busy_obj_id!=ULONG_MAX );
398 0 : ctx->bank_busy[ i ] = fd_fseq_join( fd_topo_obj_laddr( topo, busy_obj_id ) );
399 0 : if( FD_UNLIKELY( !ctx->bank_busy[ i ] ) ) FD_LOG_ERR(( "banking tile %lu has no busy flag", i ));
400 0 : }
401 :
402 0 : for( ulong i=0UL; i<tile->in_cnt-2UL; i++ ) {
403 0 : fd_topo_link_t * link = &topo->links[ tile->in_link_id[ i ] ];
404 0 : fd_topo_wksp_t * link_wksp = &topo->workspaces[ topo->objs[ link->dcache_obj_id ].wksp_id ];
405 0 : FD_TEST( strcmp( link->name, "replay_poh" )==0 );
406 :
407 0 : ctx->bank_in[ i ].mem = link_wksp->wksp;
408 0 : ctx->bank_in[ i ].chunk0 = fd_dcache_compact_chunk0( ctx->bank_in[i].mem, link->dcache );
409 0 : ctx->bank_in[ i ].wmark = fd_dcache_compact_wmark ( ctx->bank_in[i].mem, link->dcache, link->mtu );
410 0 : }
411 :
412 0 : FD_TEST( strcmp( topo->links[ tile->in_link_id[ ctx->stake_in_idx ] ].name, "stake_out" )==0 );
413 0 : ctx->stake_in.mem = topo->workspaces[ topo->objs[ topo->links[ tile->in_link_id[ ctx->stake_in_idx ] ].dcache_obj_id ].wksp_id ].wksp;
414 0 : ctx->stake_in.chunk0 = fd_dcache_compact_chunk0( ctx->stake_in.mem, topo->links[ tile->in_link_id[ ctx->stake_in_idx ] ].dcache );
415 0 : ctx->stake_in.wmark = fd_dcache_compact_wmark ( ctx->stake_in.mem, topo->links[ tile->in_link_id[ ctx->stake_in_idx ] ].dcache, topo->links[ tile->in_link_id[ ctx->stake_in_idx ] ].mtu );
416 :
417 0 : FD_TEST( strcmp( topo->links[ tile->in_link_id[ ctx->pack_in_idx ] ].name, "pack_replay" )==0 );
418 0 : ctx->pack_in.mem = topo->workspaces[ topo->objs[ topo->links[ tile->in_link_id[ ctx->pack_in_idx ] ].dcache_obj_id ].wksp_id ].wksp;
419 0 : ctx->pack_in.chunk0 = fd_dcache_compact_chunk0( ctx->stake_in.mem, topo->links[ tile->in_link_id[ ctx->pack_in_idx ] ].dcache );
420 0 : ctx->pack_in.wmark = fd_dcache_compact_wmark ( ctx->stake_in.mem, topo->links[ tile->in_link_id[ ctx->pack_in_idx ] ].dcache, topo->links[ tile->in_link_id[ ctx->pack_in_idx ] ].mtu );
421 :
422 0 : ctx->shred_out_mem = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ 0 ] ].dcache_obj_id ].wksp_id ].wksp;
423 0 : ctx->shred_out_chunk0 = fd_dcache_compact_chunk0( ctx->shred_out_mem, topo->links[ tile->out_link_id[ 0 ] ].dcache );
424 0 : ctx->shred_out_wmark = fd_dcache_compact_wmark ( ctx->shred_out_mem, topo->links[ tile->out_link_id[ 0 ] ].dcache, topo->links[ tile->out_link_id[ 0 ] ].mtu );
425 0 : ctx->shred_out_chunk = ctx->shred_out_chunk0;
426 :
427 0 : ctx->pack_out_mcache = topo->links[ tile->out_link_id[ 1 ] ].mcache;
428 0 : ctx->pack_out_sync = fd_mcache_seq_laddr( ctx->pack_out_mcache );
429 0 : ctx->pack_out_depth = fd_mcache_depth( ctx->pack_out_mcache );
430 0 : ctx->pack_out_seq = fd_mcache_seq_query( ctx->pack_out_sync );
431 :
432 0 : ctx->pack_out_mem = topo->workspaces[ topo->objs[ topo->links[ tile->out_link_id[ 1 ] ].dcache_obj_id ].wksp_id ].wksp;
433 0 : ctx->pack_out_chunk0 = fd_dcache_compact_chunk0( ctx->pack_out_mem, topo->links[ tile->out_link_id[ 1 ] ].dcache );
434 0 : ctx->pack_out_wmark = fd_dcache_compact_wmark ( ctx->pack_out_mem, topo->links[ tile->out_link_id[ 1 ] ].dcache, topo->links[ tile->out_link_id[ 1 ] ].mtu );
435 0 : ctx->pack_out_chunk = ctx->pack_out_chunk0;
436 :
437 0 : ulong scratch_top = FD_SCRATCH_ALLOC_FINI( l, 1UL );
438 0 : if( FD_UNLIKELY( scratch_top > (ulong)scratch + scratch_footprint( tile ) ) )
439 0 : FD_LOG_ERR(( "scratch overflow %lu %lu %lu", scratch_top - (ulong)scratch - scratch_footprint( tile ), scratch_top, (ulong)scratch + scratch_footprint( tile ) ));
440 0 : }
441 :
442 : /* One tick, one microblock, and one leader update. */
443 0 : #define STEM_BURST (3UL)
444 :
445 : /* See explanation in fd_pack */
446 0 : #define STEM_LAZY (128L*3000L)
447 :
448 0 : #define STEM_CALLBACK_CONTEXT_TYPE fd_poh_ctx_t
449 0 : #define STEM_CALLBACK_CONTEXT_ALIGN alignof(fd_poh_ctx_t)
450 :
451 0 : #define STEM_CALLBACK_DURING_HOUSEKEEPING during_housekeeping
452 0 : #define STEM_CALLBACK_AFTER_CREDIT after_credit
453 0 : #define STEM_CALLBACK_DURING_FRAG during_frag
454 0 : #define STEM_CALLBACK_AFTER_FRAG after_frag
455 :
456 : #include "../../disco/stem/fd_stem.c"
457 :
458 : fd_topo_run_tile_t fd_tile_poh_int = {
459 : .name = "pohi",
460 : .populate_allowed_seccomp = NULL,
461 : .populate_allowed_fds = NULL,
462 : .scratch_align = scratch_align,
463 : .scratch_footprint = scratch_footprint,
464 : .privileged_init = privileged_init,
465 : .unprivileged_init = unprivileged_init,
466 : .run = stem_run,
467 : };
|