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