Line data Source code
1 : #ifndef HEADER_fd_src_ballet_pack_fd_pack_h
2 : #define HEADER_fd_src_ballet_pack_fd_pack_h
3 :
4 : /* fd_pack defines methods that prioritizes Solana transactions,
5 : selecting a subset (potentially all) and ordering them to attempt to
6 : maximize the overall profitability of the validator. */
7 :
8 : #include "../../ballet/fd_ballet_base.h"
9 : #include "../../ballet/txn/fd_txn.h"
10 : #include "fd_est_tbl.h"
11 : #include "fd_microblock.h"
12 : #include "fd_pack_rebate_sum.h"
13 :
14 0 : #define FD_PACK_ALIGN (128UL)
15 :
16 44214 : #define FD_PACK_MAX_BANK_TILES 62UL
17 :
18 : /* NOTE: THE FOLLOWING CONSTANTS ARE CONSENSUS CRITICAL AND CANNOT BE
19 : CHANGED WITHOUT COORDINATING WITH ANZA. */
20 18072 : #define FD_PACK_MAX_COST_PER_BLOCK (48000000UL)
21 318 : #define FD_PACK_MAX_VOTE_COST_PER_BLOCK (36000000UL)
22 2085 : #define FD_PACK_MAX_WRITE_COST_PER_ACCT (12000000UL)
23 27163617 : #define FD_PACK_FEE_PER_SIGNATURE (5000UL) /* In lamports */
24 :
25 : /* Each block is limited to 32k parity shreds. We don't want pack to
26 : produce a block with so many transactions we can't shred it, but the
27 : correspondence between transactions and parity shreds is somewhat
28 : complicated, so we need to use conservative limits.
29 :
30 : Except for the final batch in the block, the current version of the
31 : shred tile shreds microblock batches of size (25431, 63671] bytes,
32 : including the microblock headers, but excluding the microblock count.
33 : The worst case size by bytes/parity shred is a 25871 byte microblock
34 : batch, which produces 31 parity shreds. The final microblock batch,
35 : however, may be as bad as 48 bytes triggering the creation of 17
36 : parity shreds. This gives us a limit of floor((32k - 17)/31)*25871 +
37 : 48 = 27,319,824 bytes.
38 :
39 : To get this right, the pack tile needs to add in the 48-byte
40 : microblock headers for each microblock, and we also need to subtract
41 : out the tick bytes, which aren't known until PoH initialization is
42 : complete.
43 :
44 : Note that the number of parity shreds in each FEC set is always at
45 : least as many as the number of data shreds, so we don't need to
46 : consider the data shreds limit. */
47 3 : #define FD_PACK_MAX_DATA_PER_BLOCK (((32UL*1024UL-17UL)/31UL)*25871UL + 48UL)
48 :
49 : /* Optionally allow up to 1M shreds per block for benchmarking. */
50 0 : #define LARGER_MAX_DATA_PER_BLOCK (((32UL*32UL*1024UL-17UL)/31UL)*25871UL + 48UL)
51 :
52 : /* ---- End consensus-critical constants */
53 :
54 27192687 : #define FD_TXN_P_FLAGS_IS_SIMPLE_VOTE ( 1U)
55 13581750 : #define FD_TXN_P_FLAGS_BUNDLE ( 2U)
56 13581876 : #define FD_TXN_P_FLAGS_INITIALIZER_BUNDLE ( 4U)
57 126 : #define FD_TXN_P_FLAGS_SANITIZE_SUCCESS ( 8U)
58 276 : #define FD_TXN_P_FLAGS_EXECUTE_SUCCESS (16U)
59 0 : #define FD_TXN_P_FLAGS_FEES_ONLY (32U)
60 :
61 171 : #define FD_TXN_P_FLAGS_RESULT_MASK (0xFF000000U)
62 :
63 : /* A bundle is a sequence of between 1 and FD_PACK_MAX_TXN_PER_BUNDLE
64 : transactions (both inclusive) that executes and commits atomically.
65 : */
66 4059 : #define FD_PACK_MAX_TXN_PER_BUNDLE 5UL
67 :
68 :
69 : /* The Solana network and Firedancer implementation details impose
70 : several limits on what pack can produce. These limits are grouped in
71 : this one struct fd_pack_limits_t, which is just a convenient way to
72 : pass them around. The limits listed below are arithmetic limits.
73 : The limits imposed by practical constraints are almost certainly
74 : much, much tighter. */
75 : struct fd_pack_limits {
76 : /* max_{cost, vote_cost}_per_block, max_write_cost_per_acct are
77 : consensus-critical limits and must be agreed on cluster-wide. A
78 : block that consumes more than max_cost_per_block cost units
79 : (closely related to, but not identical to CUs) in total is invalid.
80 : Similarly, a block where the sum of the cost of all vote
81 : transactions exceeds max_vote_cost_per_block cost units is invalid.
82 : Similarly, a block in where the sum of the cost of all transactions
83 : that write to a given account exceeds max_write_cost_per_acct is
84 : invalid. */
85 : ulong max_cost_per_block; /* in [0, ULONG_MAX) */
86 : ulong max_vote_cost_per_block; /* in [0, max_cost_per_block] */
87 : ulong max_write_cost_per_acct; /* in [0, max_cost_per_block] */
88 :
89 : /* max_data_bytes_per_block is derived from consensus-critical limits
90 : on the number of shreds in a block, but is not directly enforced.
91 : Separation of concerns means that it's not a good idea for pack to
92 : know exactly how the block will be shredded, but at the same time,
93 : we don't want to end up in a situation where we produced a block
94 : that had too many shreds, because the shred tile's only recourse
95 : would be to kill the block. To address this, pack limits the size
96 : of the data it puts into the block to a limit that we can prove
97 : will never cause the shred tile to produce too many shreds.
98 :
99 : This limit includes transaction and microblock headers for
100 : non-empty microblocks that pack produces. */
101 : ulong max_data_bytes_per_block; /* in [0, ULONG_MAX - 183] */
102 :
103 : /* max_txn_per_microblock and max_microblocks_per_block are
104 : Firedancer-imposed implementation limits to bound the amount of
105 : memory consumption that pack uses. Pack will produce microblocks
106 : with no more than max_txn_per_microblock transactions.
107 : Additionally, once pack produces max_microblocks_per_block
108 : non-empty microblocks in a block, all subsequent attempts to
109 : schedule a microblock will return an empty microblock until
110 : fd_pack_end_block is called. */
111 : ulong max_txn_per_microblock; /* in [0, 16777216] */
112 : ulong max_microblocks_per_block; /* in [0, 1e12) */
113 :
114 : };
115 : typedef struct fd_pack_limits fd_pack_limits_t;
116 :
117 :
118 : /* Forward declare opaque handle */
119 : struct fd_pack_private;
120 : typedef struct fd_pack_private fd_pack_t;
121 :
122 : /* fd_pack_{align,footprint} return the required alignment and
123 : footprint in bytes for a region of memory to be used as a pack
124 : object.
125 :
126 : pack_depth sets the maximum number of pending transactions that pack
127 : stores and may eventually schedule. pack_depth must be at least 4.
128 :
129 : If bundle_meta_sz is non-zero, then the bundle-related functions on
130 : this pack object can be used, and it can schedule bundles.
131 : Additionally, if bundle_meta_sz is non-zero, then a region of size
132 : bundle_meta_sz bytes (with no additional alignment) will be reserved
133 : for each bundle.
134 :
135 : Note: if you'd like to use bundles, but don't require metadata for
136 : the bundles, simply use a small positive value (e.g. 1), always pass
137 : NULL in insert_bundle_fini, and never call fd_pack_peek_bundle_meta.
138 :
139 : bank_tile_cnt sets the number of bank tiles to which this pack object
140 : can schedule transactions. bank_tile_cnt must be in [1,
141 : FD_PACK_MAX_BANK_TILES].
142 :
143 : limits sets various limits for the blocks and microblocks that pack
144 : can produce. */
145 :
146 0 : FD_FN_CONST static inline ulong fd_pack_align ( void ) { return FD_PACK_ALIGN; }
147 :
148 : FD_FN_PURE ulong
149 : fd_pack_footprint( ulong pack_depth,
150 : ulong bundle_meta_sz,
151 : ulong bank_tile_cnt,
152 : fd_pack_limits_t const * limits );
153 :
154 :
155 : /* fd_pack_new formats a region of memory to be suitable for use as a
156 : pack object. mem is a non-NULL pointer to a region of memory in the
157 : local address space with the required alignment and footprint.
158 : pack_depth, bundle_meta_sz, bank_tile_cnt, and limits are as above.
159 : rng is a local join to a random number generator used to perturb
160 : estimates.
161 :
162 : Returns `mem` (which will be properly formatted as a pack object) on
163 : success and NULL on failure. Logs details on failure. The caller
164 : will not be joined to the pack object when this function returns. */
165 : void * fd_pack_new( void * mem,
166 : ulong pack_depth,
167 : ulong bundle_meta_sz,
168 : ulong bank_tile_cnt,
169 : fd_pack_limits_t const * limits,
170 : fd_rng_t * rng );
171 :
172 : /* fd_pack_join joins the caller to the pack object. Every successful
173 : join should have a matching leave. Returns mem. */
174 : fd_pack_t * fd_pack_join( void * mem );
175 :
176 :
177 : /* fd_pack_avail_txn_cnt returns the number of transactions that this
178 : pack object has available to schedule but that have not been
179 : scheduled yet. pack must be a valid local join. The return value
180 : will be in [0, pack_depth). */
181 :
182 : /* For performance reasons, implement this here. The offset is STATIC_ASSERTed
183 : in fd_pack.c. */
184 48894 : #define FD_PACK_PENDING_TXN_CNT_OFF 72
185 : FD_FN_PURE static inline ulong
186 48894 : fd_pack_avail_txn_cnt( fd_pack_t const * pack ) {
187 48894 : return *((ulong const *)((uchar const *)pack + FD_PACK_PENDING_TXN_CNT_OFF));
188 48894 : }
189 :
190 : /* fd_pack_current_block_cost returns the number of CUs that have been
191 : scheduled in the current block, net of any rebates. It should be
192 : between 0 and the specified value of max_cost_per_block, but it can
193 : be slightly higher due to temporary cost model nonsense. Due to
194 : rebates, this number may decrease as the block progresses. pack must
195 : be a valid local join. */
196 : FD_FN_PURE ulong fd_pack_current_block_cost( fd_pack_t const * pack );
197 :
198 : /* fd_pack_bank_tile_cnt: returns the value of bank_tile_cnt provided in
199 : pack when the pack object was initialized with fd_pack_new. pack
200 : must be a valid local join. The result will be in [1,
201 : FD_PACK_MAX_BANK_TILES]. */
202 : FD_FN_PURE ulong fd_pack_bank_tile_cnt( fd_pack_t const * pack );
203 :
204 : /* fd_pack_set_block_limits: Updates the limits provided fd_pack_new to
205 : the new values. Any future microblocks produced by this pack object
206 : will not cause a block to have more than max_microblocks_per_block
207 : non-empty microblocks or more than max_data_bytes_per_block data
208 : bytes (counting microblock headers as before). Limits are inclusive,
209 : as per usual (i.e. a block may have exactly
210 : max_microblocks_per_block microblocks, but not more). pack must be
211 : a valid local join.
212 :
213 : The typical place to call this is immediately after
214 : fd_pack_end_block; if this is called after some microblocks have been
215 : produced for the current block, and the current block already exceeds
216 : the limits, all the remaining microblocks in the block will be empty,
217 : but the call is valid. */
218 : void fd_pack_set_block_limits( fd_pack_t * pack, ulong max_microblocks_per_block, ulong max_data_bytes_per_block );
219 :
220 : /* Return values for fd_pack_insert_txn_fini: Non-negative values
221 : indicate the transaction was accepted and may be returned in a future
222 : microblock. Negative values indicate that the transaction was
223 : rejected and will never be returned in a future microblock.
224 : Transactions can be rejected through no fault of their own, so it
225 : doesn't necessarily imply bad behavior.
226 :
227 : The non-negative (success) codes are essentially a bitflag of two
228 : bits:
229 : * whether the transaction met the criteria for a simple vote or not,
230 : * whether this transaction replaced a previously accepted, low
231 : priority transaction, rather than being accepted in addition to all
232 : the previously accepted transactions. Since pack maintains a heap
233 : with a fixed max size of pack_depth, replacing transaction is
234 : necessary whenever the heap is full.
235 :
236 : The negative (failure) codes are a normal enumeration (not a
237 : bitflag).
238 : * PRIORITY: pack's heap was full and the transaction's priority was
239 : lower than the worst currently accepted transaction.
240 : * DUPLICATE: the transaction is a duplicate of a currently accepted
241 : transaction.
242 : * UNAFFORDABLE: the fee payer could not afford the transaction fee
243 : (not yet implemented).
244 : * ADDR_LUT: the transaction tried to load an account from an address
245 : lookup table, which is not yet supported.
246 : * EXPIRED: the transaction was already expired upon insertion based
247 : on the provided value of expires_at compared to the last call to
248 : fd_pack_expire_before.
249 : * TOO_LARGE: the transaction requested too many CUs and would never
250 : be scheduled if it had been accepted.
251 : * ACCOUNT_CNT: the transaction tried to load more than 64 account
252 : addresses.
253 : * DUPLICATE_ACCT: the transaction included an account address twice
254 : in its list of account addresses to load.
255 : * ESTIMATION_FAIL: estimation of the transaction's compute cost and
256 : fee failed, typically because the transaction contained a
257 : malformed ComputeBudgetProgram instruction.
258 : * WRITES_SYSVAR: the transaction attempts to write-lock a sysvar.
259 : Write-locking a sysvar can cause heavy contention. Agave
260 : solves this by downgrading these to read locks, but we instead
261 : solve it by refusing to pack such transactions.
262 : * BUNDLE_BLACKLIST: bundles are enabled and the transaction uses an
263 : account in the bundle blacklist.
264 :
265 : NOTE: The corresponding enum in metrics.xml must be kept in sync
266 : with any changes to these return values. */
267 0 : #define FD_PACK_INSERT_ACCEPT_VOTE_REPLACE ( 3)
268 494592 : #define FD_PACK_INSERT_ACCEPT_NONVOTE_REPLACE ( 2)
269 37596 : #define FD_PACK_INSERT_ACCEPT_VOTE_ADD ( 1)
270 13049508 : #define FD_PACK_INSERT_ACCEPT_NONVOTE_ADD ( 0)
271 0 : #define FD_PACK_INSERT_REJECT_PRIORITY ( -1)
272 : #define FD_PACK_INSERT_REJECT_DUPLICATE ( -2)
273 0 : #define FD_PACK_INSERT_REJECT_UNAFFORDABLE ( -3)
274 : #define FD_PACK_INSERT_REJECT_ADDR_LUT ( -4)
275 12 : #define FD_PACK_INSERT_REJECT_EXPIRED ( -5)
276 0 : #define FD_PACK_INSERT_REJECT_TOO_LARGE ( -6)
277 3 : #define FD_PACK_INSERT_REJECT_ACCOUNT_CNT ( -7)
278 3 : #define FD_PACK_INSERT_REJECT_DUPLICATE_ACCT ( -8)
279 3 : #define FD_PACK_INSERT_REJECT_ESTIMATION_FAIL ( -9)
280 93 : #define FD_PACK_INSERT_REJECT_WRITES_SYSVAR (-10)
281 0 : #define FD_PACK_INSERT_REJECT_BUNDLE_BLACKLIST (-11)
282 :
283 : /* The FD_PACK_INSERT_{ACCEPT, REJECT}_* values defined above are in the
284 : range [-FD_PACK_INSERT_RETVAL_OFF,
285 : -FD_PACK_INSERT_RETVAL_OFF+FD_PACK_INSERT_RETVAL_CNT ) */
286 0 : #define FD_PACK_INSERT_RETVAL_OFF 11
287 0 : #define FD_PACK_INSERT_RETVAL_CNT 15
288 :
289 : FD_STATIC_ASSERT( FD_PACK_INSERT_REJECT_BUNDLE_BLACKLIST>=-FD_PACK_INSERT_RETVAL_OFF, pack_retval );
290 : FD_STATIC_ASSERT( FD_PACK_INSERT_ACCEPT_VOTE_REPLACE<FD_PACK_INSERT_RETVAL_CNT-FD_PACK_INSERT_RETVAL_OFF, pack_retval );
291 :
292 : /* fd_pack_insert_txn_{init,fini,cancel} execute the process of
293 : inserting a new transaction into the pool of available transactions
294 : that may be scheduled by the pack object.
295 :
296 : fd_pack_insert_txn_init returns a piece of memory from the txnmem
297 : region where the transaction should be stored. The lifetime of this
298 : memory is managed by fd_pack as explained below.
299 :
300 : Every call to fd_pack_insert_init must be paired with a call to
301 : exactly one of _fini or _cancel. Calling fd_pack_insert_txn_fini
302 : finalizes the transaction insert process and makes the newly-inserted
303 : transaction available for scheduling. Calling
304 : fd_pack_insert_txn_cancel aborts the transaction insertion process.
305 : The txn pointer passed to _fini or _cancel must come from the most
306 : recent call to _init.
307 :
308 : The caller of these methods should not retain any read or write
309 : interest in the transaction after _fini or _cancel have been called.
310 :
311 : expires_at (for _fini only) bounds the lifetime of the inserted
312 : transaction. No particular unit is prescribed, and it need not be
313 : higher than the previous call to txn_fini. If fd_pack_expire_before
314 : has been previously called with a value larger (strictly) than the
315 : provided expires_at, the transaction will be rejected with EXPIRED.
316 : See fd_pack_expire_before for more details.
317 :
318 : pack must be a local join of a pack object. From the caller's
319 : perspective, these functions cannot fail, though pack may reject a
320 : transaction for a variety of reasons. fd_pack_insert_txn_fini
321 : returns one of the FD_PACK_INSERT_ACCEPT_* or FD_PACK_INSERT_REJECT_*
322 : codes explained above.
323 : */
324 : fd_txn_e_t * fd_pack_insert_txn_init ( fd_pack_t * pack );
325 : int fd_pack_insert_txn_fini ( fd_pack_t * pack, fd_txn_e_t * txn, ulong expires_at );
326 : void fd_pack_insert_txn_cancel( fd_pack_t * pack, fd_txn_e_t * txn );
327 :
328 : /* fd_pack_insert_bundle_{init,fini,cancel} are parallel to the
329 : similarly named fd_pack_insert_txn functions but can be used to
330 : insert a bundle instead of a transaction.
331 :
332 : fd_pack_insert_bundle_init populates and returns bundle.
333 : Specifically, it populates bundle[0], ... bundle[txn_cnt-1] with
334 : pointers to fd_txn_p_t structs that should receive a new transaction.
335 : The pointers themselves should not be changed which is what the const
336 : indicates, but the contents of the fd_txn_p_t structs must be changed
337 : in order for this to be useful. bundle must be a pointer to the
338 : first element of an array of at least txn_cnt pointers.
339 :
340 : The bundle consists of the transactions in the order they are
341 : provided. I.e. bundle[0] will execute first in the bundle.
342 :
343 : Like with insert_txn, every call to fd_pack_insert_bundle_init must
344 : be paired with a call to exactly one of _fini or _cancel. Calling
345 : fd_pack_insert_bundle_fini finalizes the bundle insertion process and
346 : makes the newly-inserted bundle available for scheduling. Calling
347 : fd_pack_insert_bundle_cancel aborts the transaction insertion
348 : process. There can be at most two outstanding bundles, of which one
349 : should be an initializer bundle. The bundle argument passed to _fini
350 : or _cancel must be the return value of a call to _init with the same
351 : value of txn_cnt. Additionally, it is okay to interleave calls to
352 : the insert_txn family of functions with calls to the insert_bundle
353 : family of functions.
354 :
355 : The caller of these methods should not retain any read or write
356 : interest in the fd_txn_p_t structs that the entries of bundle
357 : point to after _fini or _cancel have been called.
358 :
359 : expires_at has the same meaning as above. Although transactions in
360 : the bundle may have different recent blockhashes, all transactions in
361 : the bundle have the same expires_at value, since if one expires, the
362 : whole bundle becomes invalid.
363 :
364 : If initializer_bundle is non-zero, this bundle will be inserted at
365 : the front of the bundle queue so that it is the next bundle
366 : scheduled. Otherwise, the bundle will be inserted at the back of the
367 : bundle queue, and will be scheduled in FIFO order with the rest of
368 : the bundles. If an initializer bundle is already present in pack's
369 : pending transactions, that bundle will be deleted. Additionally, if
370 : initializer_bundle is non-zero, the transactions in the bundle will
371 : not be checked against the bundle blacklist; otherwise, the check
372 : will be performed as normal. See the section below on initializer
373 : bundles for more details.
374 :
375 : Other than the blacklist check, transactions in a bundle are subject
376 : to the same checks as other transactions. If any transaction in the
377 : bundle fails validation, the whole bundle will be rejected.
378 :
379 : _fini also accepts bundle_meta, an optional opaque pointer to a
380 : region of memory of size bundle_meta_sz (as provided in pack_new).
381 : If bundle_meta is non-NULL, the contents of the memory will be copied
382 : to a metadata region associated with this bundle and can be retrieved
383 : later with fd_pack_peek_bundle_meta. The contents of bundle_meta is
384 : not retrievable if initializer_bundle is non-zero, so you may wish to
385 : just pass NULL in that case. This function does not retain any
386 : interest in the contents of bundle_meta after it returns.
387 :
388 : txn_cnt must be in [1, MAX_TXN_PER_BUNDLE]. A txn_cnt of 1 inserts a
389 : single-transaction bundle which is transaction with extremely high
390 : priority. That said, inserting transactions as bundles instead of
391 : transactions can hurt performance and throughput by introducing
392 : unnecessary stalls.
393 :
394 : fd_pack_insert_bundle_fini returns one of the FD_PACK_INSERT_ACCEPT_*
395 : or FD_PACK_INSERT_REJECT_* codes explained above. If there are
396 : multiple reasons for rejecting a bundle, the which of the reasons it
397 : returns is unspecified.
398 :
399 : These functions must not be called if the pack object was initialized
400 : with bundle_meta_sz==0. */
401 :
402 : fd_txn_e_t * const * fd_pack_insert_bundle_init ( fd_pack_t * pack, fd_txn_e_t * * bundle, ulong txn_cnt );
403 : int fd_pack_insert_bundle_fini ( fd_pack_t * pack, fd_txn_e_t * const * bundle, ulong txn_cnt,
404 : ulong expires_at, int initializer_bundle, void const * bundle_meta );
405 : void fd_pack_insert_bundle_cancel( fd_pack_t * pack, fd_txn_e_t * const * bundle, ulong txn_cnt );
406 :
407 :
408 : /* =========== More details about initializer bundles ===============
409 : Initializer bundles are a special type of bundle with special support
410 : from the pack object to facilitate preparing on-chain state for the
411 : execution of bundles by this validator. This design is a bit
412 : complicated, but it eliminates excessive coupling between pack and
413 : block engine details.
414 :
415 : The pack object maintains a small state machine (initializer bundle
416 : abbreviated IB):
417 :
418 : [Not Initialized] ------------------------->|
419 : ^ | Schedule an
420 : | End Rebate shows | IB
421 : | block IB failed |
422 : |<----------[Failed]--------------| v
423 : | --===[Pending]
424 : |<------------------------------/ ^ |
425 : | End block /---| |
426 : | | | Rebate shows
427 : | Schedule | | IB succeeded
428 : | another IB | |
429 : | End block | V
430 : -----------------------------------===[Ready]
431 :
432 :
433 : When attempting to schedule a bundle the pack object checks the
434 : state, and employs the following rules:
435 : * [Not Initialized]: If the top bundle is an IB, schedule it,
436 : removing it like normal, then transition to [Pending]. Otherwise,
437 : do not schedule a bundle.
438 : * [Pending]: Do not schedule a bundle.
439 : * [Failed]: Do not schedule a bundle
440 : * [Ready]: Attempt to schedule the next bundle. If scheduling an IB,
441 : transition to [Pending].
442 :
443 : As described in the state machine, ending the block (via
444 : fd_pack_end_block) transitions to [Not Initialized], and calls to
445 : fd_pack_rebate_cus control the transition out of [Pending].
446 :
447 : This design supports a typical block engine system where some state
448 : may need to be initialized at the start of the slot and some state
449 : may need to change between runs of transactions (e.g. 5 transactions
450 : from block builder A followed by 5 transactions from block builder
451 : B). This can be done by inserting an initializer bundle whenever the
452 : top non-initializer bundle's metadata state (retrievable with
453 : fd_pack_peek_bundle_meta) doesn't match the current on-chain state.
454 : Since the initializer bundle will execute before the bundle that was
455 : previously the top one, by the time the non-initializer bundle
456 : executes, the on-chain state will be correctly configured. In this
457 : scheme, in the rare case that an initializer bundle was inserted but
458 : never executed, it should be deleted at the end of the slot.
459 :
460 : If at the start of the slot, it is determined that the on-chain state
461 : is in good shape, the state machine can transition directly to
462 : [Ready] by calling fd_pack_set_initializer_bundles_ready.
463 :
464 : Initializer bundles are not exempt from expiration, but it should not
465 : be a problem if they are always inserted with the most recent
466 : blockhash and deleted at the end of the slot.
467 :
468 : Additionally, a bundle marked as an IB is exempted from the bundle
469 : account blacklist checks. For this reason, it's important that IB be
470 : generated by trusted code with minimal or sanitized
471 : attacker-controlled input. */
472 :
473 :
474 : /* fd_pack_peek_bundle_meta returns a constant pointer to the bundle
475 : metadata associated with the bundle currently in line to be scheduled
476 : next, or NULL in any of the following cases:
477 : * There are no bundles
478 : * The bundle currently in line to be scheduled next is an IB
479 : * The bundle state is currently [Pending] or [Failed].
480 :
481 : The lifetime of the returned pointer is until the next pack insert,
482 : schedule, delete, or expire call. The size of the region pointed to
483 : by the returned pointer is bundle_meta_sz. If this bundle was
484 : inserted with bundle_meta==NULL, then the contents of the region
485 : pointed to by the returned pointer are arbitrary, but it will be safe
486 : to read.
487 :
488 : Pack doesn't do anything special to ensure the returned pointer
489 : points to memory with any particular alignment. It will naturally
490 : have an alignment of at least GCD( 64, bundle_meta_sz ). */
491 : void const * fd_pack_peek_bundle_meta( fd_pack_t const * pack );
492 :
493 : /* fd_pack_set_initializer_bundles_ready sets the IB state machine state
494 : (see long initializer bundle comment above) to the [Ready] state.
495 : This function makes it easy to use bundles without initializer
496 : bundles. pack must be a valid local join. */
497 : void fd_pack_set_initializer_bundles_ready( fd_pack_t * pack );
498 :
499 : /* fd_pack_schedule_next_microblock schedules pending transactions.
500 : These transaction either form a microblock, which is a set of
501 : non-conflicting transactions, or a bundle. The semantics of this
502 : function are a bit different depending on which one it picks, but
503 : there are some reasons why they both use this function.
504 :
505 : For both codepaths, pack must be a local join of a pack object.
506 :
507 : Microblock case:
508 : Transactions part of the scheduled microblock are copied to out in no
509 : particular order. The cumulative cost of these transactions will not
510 : exceed total_cus, and the number of transactions will not exceed the
511 : value of max_txn_per_microblock given in fd_pack_new.
512 :
513 : The block will not contain more than
514 : vote_fraction*max_txn_per_microblock votes, and votes in total will
515 : not consume more than vote_fraction*total_cus of the microblock.
516 :
517 : Bundle case:
518 : Transactions part of the scheduled bundled are copied in execution
519 : order (i.e. out[0] must be executed first). The number of
520 : transactions will not exceed FD_PACK_MAX_TXN_PER_BUNDLE.
521 : max_txn_per_microblock, total_cus, and vote_fraction are ignored,
522 : though the block-level limits are respected.
523 :
524 : Both cases:
525 : The non_execution_cus and requested_exec_plus_acct_data_cus fields of
526 : each transaction will be populated with the non execution CUs and
527 : requested execution CUs (including cus derived from the requested
528 : loaded accounts data size), respectively. The sum of these two
529 : values is the total cost of the transaction, i.e. what is used for
530 : all limits, including the total_cus value. The lower 3 bits of the
531 : flags field will be populated (simple vote, bundle, initializer
532 : bundle). Inspecting these flags is the proper way to tell which
533 : codepath executed.
534 :
535 : Returns the number of transactions in the scheduled microblock or
536 : bundle. The return value may be 0 if there are no eligible
537 : transactions at the moment. */
538 :
539 : ulong fd_pack_schedule_next_microblock( fd_pack_t * pack, ulong total_cus, float vote_fraction, ulong bank_tile, fd_txn_p_t * out );
540 :
541 :
542 : /* fd_pack_rebate_cus adjusts the compute unit accounting for the
543 : specified transactions to take into account the actual consumed CUs
544 : after execution. When a transaction is scheduled by
545 : schedule_next_microblock, pack assumes that it uses all the CUs it
546 : requests for the purposes of several CU limits. If it doesn't use
547 : all the requested CUs, this function "rebates" them to pack so that
548 : they can be consumed by a different transaction in the block.
549 :
550 : pack must be a valid local join of a pack object. rebate must point
551 : to a valid rebate report produced by fd_pack_rebate_sum_t.
552 :
553 : IMPORTANT: CU limits are reset at the end of each block, so this
554 : should not be called for transactions from a prior block.
555 : Specifically, there must not be a call to fd_pack_end_block between
556 : the call to schedule_next_microblock this is paired with and the call
557 : to rebate_cus.
558 :
559 : This function operates independently of microblock_complete. In
560 : general, you probably need to call both. microblock_complete must be
561 : called before scheduling another microblock to that bank tile, while
562 : rebate_cus is optional and has much more relaxed ordering
563 : constraints. The restriction about intervening calls to end_block
564 : and that this must come after schedule_next_microblock are the only
565 : ordering constraints. */
566 : void fd_pack_rebate_cus( fd_pack_t * pack, fd_pack_rebate_t const * rebate );
567 :
568 : /* fd_pack_microblock_complete signals that the bank_tile with index
569 : bank_tile has completed its previously scheduled microblock. This
570 : permits the scheduling of transactions that conflict with the
571 : previously scheduled microblock. It is safe to call this multiple
572 : times after a microblock or even if bank_tile does not have a
573 : previously scheduled; in this case, the function will return 0 and
574 : act as a no-op. Returns 1 if the bank_tile had an outstanding,
575 : previously scheduled microblock to mark as completed. */
576 : int fd_pack_microblock_complete( fd_pack_t * pack, ulong bank_tile );
577 :
578 : /* fd_pack_expire_before deletes all available transactions with
579 : expires_at values strictly less than expire_before. pack must be a
580 : local join of a pack object. Returns the number of transactions
581 : deleted. Subsequent calls to fd_pack_expire_before with the same or
582 : a smaller value are no-ops. */
583 : ulong fd_pack_expire_before( fd_pack_t * pack, ulong expire_before );
584 :
585 : /* fd_pack_delete_txn removes a transaction (identified by its first
586 : signature) from the pool of available transactions. Returns 1 if the
587 : transaction was found (and then removed) and 0 if not. */
588 : int fd_pack_delete_transaction( fd_pack_t * pack, fd_ed25519_sig_t const * sig0 );
589 :
590 : /* fd_pack_end_block resets some state to prepare for the next block.
591 : Specifically, the per-block limits are cleared and transactions in
592 : the microblocks scheduled after the call to this function are allowed
593 : to conflict with transactions in microblocks scheduled before the
594 : call to this function, even within gap microblocks. */
595 : void fd_pack_end_block( fd_pack_t * pack );
596 :
597 :
598 : /* fd_pack_clear_all resets the state associated with this pack object.
599 : All pending transactions are removed from the pool of available
600 : transactions and all limits are reset. */
601 : void fd_pack_clear_all( fd_pack_t * pack );
602 :
603 :
604 : /* fd_pack_metrics_write writes period metric values to the metrics
605 : system. pack must be a valid local join. */
606 : void
607 : fd_pack_metrics_write( fd_pack_t const * pack );
608 :
609 :
610 : /* fd_pack_leave leaves a local join of a pack object. Returns pack. */
611 : void * fd_pack_leave( fd_pack_t * pack );
612 : /* fd_pack_delete unformats a memory region used to store a pack object
613 : and returns ownership of the memory to the caller. Returns mem. */
614 : void * fd_pack_delete( void * mem );
615 :
616 : /* fd_pack_verify (for debugging use primarily) checks to ensure several
617 : invariants are satisfied. scratch must point to the first byte of a
618 : piece of memory meeting the same alignment and footprint constraints
619 : as pack. Returns 0 on success and a negative value on failure
620 : (logging a warning with details). */
621 : int fd_pack_verify( fd_pack_t * pack, void * scratch );
622 :
623 : FD_PROTOTYPES_END
624 : #endif /* HEADER_fd_src_ballet_pack_fd_pack_h */
|