LCOV - code coverage report
Current view: top level - disco/pack - fd_pack.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 37 0.0 %
Date: 2026-11-11 12:40:43 Functions: 0 102 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_disco_pack_fd_pack_h
       2             : #define HEADER_fd_src_disco_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             : #include "fd_pack_acct_blocklist.h"
      15             : #include "../metrics/generated/fd_metrics_enums.h"
      16             : 
      17           0 : #define FD_PACK_ALIGN     (128UL)
      18             : 
      19           0 : #define FD_PACK_MAX_EXECLE_TILES 62UL
      20             : 
      21           0 : #define FD_PACK_FEE_PER_SIGNATURE           (5000UL) /* In lamports */
      22             : 
      23             : /* Each block is limited to 32k parity shreds.  We don't want pack to
      24             :    produce a block with so many transactions we can't shred it, but the
      25             :    correspondence between transactions and parity shreds is somewhat
      26             :    complicated, so we need to use conservative limits. */
      27           0 : #define FD_PACK_MAX_DATA_PER_BLOCK (FD_SHRED_BATCH_BLOCK_DATA_SZ_MAX)
      28             : 
      29             : /* ---- End consensus-critical constants */
      30             : 
      31           0 : #define FD_TXN_P_FLAGS_BUNDLE             ( 2U)
      32           0 : #define FD_TXN_P_FLAGS_INITIALIZER_BUNDLE ( 4U)
      33           0 : #define FD_TXN_P_FLAGS_SANITIZE_SUCCESS   ( 8U)
      34           0 : #define FD_TXN_P_FLAGS_EXECUTE_SUCCESS    (16U)
      35           0 : #define FD_TXN_P_FLAGS_FEES_ONLY          (32U)
      36           0 : #define FD_TXN_P_FLAGS_DURABLE_NONCE      (64U)
      37             : 
      38           0 : #define FD_TXN_P_FLAGS_RESULT_MASK  (0xFF000000U)
      39             : 
      40             : /* The percentage of the transaction fees that are burned */
      41           0 : #define FD_PACK_TXN_FEE_BURN_PCT        50UL
      42             : 
      43             : /* Durable nonce transactions don't have a fixed lifetime (see
      44             :    expire_before, etc.) but we arbitrarily give them one to prevent them
      45             :    from remaining perpetually e.g. between leader rotations.  The unit
      46             :    here is arbitrary, but 500 makes the most sense for slots.  TODO:
      47             :    make this configurable. */
      48           0 : #define FD_PACK_NONCE_SYNTHETIC_LIFETIME 500UL
      49             : 
      50             : 
      51             : /* The Solana network and Firedancer implementation details impose
      52             :    several limits on what pack can produce.  These limits are grouped in
      53             :    this one struct fd_pack_limits_t, which is just a convenient way to
      54             :    pass them around.  The limits listed below are arithmetic limits.
      55             :    The limits imposed by practical constraints are almost certainly
      56             :    much, much tighter. */
      57             : struct fd_pack_limits {
      58             :   /* max_cost_per_block, max_write_cost_per_acct are
      59             :      consensus-critical limits and must be agreed on cluster-wide.  A
      60             :      block that consumes more than max_cost_per_block cost units
      61             :      (closely related to, but not identical to CUs) in total is invalid.
      62             :      Similarly, a block in where the sum of the cost of all transactions
      63             :      that write to a given account exceeds max_write_cost_per_acct is
      64             :      invalid. */
      65             :   ulong max_cost_per_block;          /* in [0, UINT_MAX) */
      66             :   ulong max_write_cost_per_acct;     /* in [0, max_cost_per_block] */
      67             : 
      68             :   /* max_data_bytes_per_block is derived from consensus-critical limits
      69             :      on the number of shreds in a block, but is not directly enforced.
      70             :      Separation of concerns means that it's not a good idea for pack to
      71             :      know exactly how the block will be shredded, but at the same time,
      72             :      we don't want to end up in a situation where we produced a block
      73             :      that had too many shreds, because the shred tile's only recourse
      74             :      would be to kill the block.  To address this, pack limits the size
      75             :      of the data it puts into the block to a limit that we can prove
      76             :      will never cause the shred tile to produce too many shreds.
      77             :      At runtime this is how many entry bytes fit in max_shred_idx
      78             :      after FEC padding (we close a shred batch when the next
      79             :      microblock would not fit in two FEC sets).  Empty ticks are
      80             :      subtracted.  Large microblocks pad more, so the cap
      81             :      tightens.
      82             : 
      83             :      This limit includes transaction and microblock headers for
      84             :      non-empty microblocks that pack produces. */
      85             :   ulong max_data_bytes_per_block;    /* in [0, ULONG_MAX - 183] */
      86             : 
      87             :   /* max_txn_per_microblock and max_microblocks_per_block are
      88             :      Firedancer-imposed implementation limits to bound the amount of
      89             :      memory consumption that pack uses.  Pack will produce microblocks
      90             :      with no more than max_txn_per_microblock transactions.
      91             :      Additionally, once pack produces max_microblocks_per_block
      92             :      non-empty microblocks in a block, all subsequent attempts to
      93             :      schedule a microblock will return an empty microblock until
      94             :      fd_pack_end_block is called. */
      95             :   ulong max_txn_per_microblock;      /* in [0, 16777216] */
      96             :   ulong max_microblocks_per_block;   /* in [0, 1e12) */
      97             : 
      98             :   /* max_allocated_data_per_block is a consensus-critical constant that
      99             :      limits the total amount of data that can be allocated by
     100             :      transactions in a block.  This includes new accounts and extending
     101             :      existing accounts.  This limit is not especially well specified,
     102             :      and rarely comes close to being hit in production, so we use a
     103             :      conservative estimate when packing to ensure we never hit it. */
     104             :   ulong max_allocated_data_per_block; /* in [1, 100,000,000 ] */
     105             : };
     106             : typedef struct fd_pack_limits fd_pack_limits_t;
     107             : 
     108             : /* fd_pack_addr_use_t: Used for three distinct purposes:
     109             :     -  to record that an address is in use and can't be used again until
     110             :          certain microblocks finish execution
     111             :     -  to keep track of the cost of all transactions that write to the
     112             :          specified account.
     113             :     -  to keep track of the write cost for accounts referenced by
     114             :          transactions in a bundle and which transactions use which
     115             :          accounts.
     116             :    Making these separate structs might make it more clear, but then
     117             :    they'd have identical shape and result in several fd_map_dynamic sets
     118             :    of functions with identical code.  It doesn't seem like the compiler
     119             :    is very good at merging code like that, so in order to reduce code
     120             :    bloat, we'll just combine them. */
     121             : struct fd_pack_private_addr_use_record {
     122             :   fd_acct_addr_t key; /* account address */
     123             :   union {
     124             :     ulong          _;
     125             :     ulong          in_use_by;  /* Bitmask indicating which banks */
     126             :     ulong          total_cost; /* In cost units/CUs */
     127             :     struct { uint    carried_cost;   /* In cost units */
     128             :              ushort  ref_cnt;        /* In transactions */
     129             :              ushort  last_use_in; }; /* In transactions */
     130             :   };
     131             : };
     132             : typedef struct fd_pack_private_addr_use_record fd_pack_addr_use_t;
     133             : 
     134             : /* The point of this array it to keep a simple heap of the top 5
     135             :    writable accounts by cus in a given slot. The top writers heap is
     136             :    constructed and available at the end of a leader slot, after all CUs
     137             :    have been rebated. */
     138           0 : #define FD_PACK_TOP_WRITERS_CNT (5UL)
     139           0 : #define FD_PACK_TOP_WRITERS_SORT_BEFORE(writer1,writer2) ( (memcmp( (writer1).key.b, &(uchar[32]){ 0 }, FD_TXN_ACCT_ADDR_SZ ) && (writer1).total_cost>(writer2).total_cost) || !memcmp( (writer2).key.b, &(uchar[32]){ 0 }, FD_TXN_ACCT_ADDR_SZ ))
     140             : 
     141             : /* fd_pack_limit_usage_t is used to store the actual per-slot resource
     142             :    utilization.  Each utilization field has a corresponding limit field
     143             :    in fd_pack_limits_t which is greater than or equal to the utilization
     144             :    field. */
     145             : struct fd_pack_limits_usage {
     146             :   ulong block_cost;
     147             : 
     148             :   /* Contains the top 5 writers in the block. If there are less than 5
     149             :      writeable accounts, unused slots will have their pubkey zeroed out. */
     150             :   fd_pack_addr_use_t top_writers[ FD_PACK_TOP_WRITERS_CNT ];
     151             :   ulong block_data_bytes;
     152             :   ulong microblocks;
     153             :   ulong alloc;
     154             : };
     155             : 
     156             : typedef struct fd_pack_limits_usage fd_pack_limits_usage_t;
     157             : 
     158             : /* fd_pack_smallest: We want to keep track of the smallest transaction
     159             :    in each treap.  That way, if we know the amount of space left in the
     160             :    block is less than the smallest transaction in the heap, we can just
     161             :    skip the heap.  Since transactions can be deleted, etc. maintaining
     162             :    this precisely is hard, but we can maintain a conservative value
     163             :    fairly cheaply.  Since the CU limit or the byte limit can be the one
     164             :    that matters, we keep track of the smallest by both. */
     165             : struct fd_pack_smallest {
     166             :   ulong cus;
     167             :   ulong bytes;
     168             : };
     169             : typedef struct fd_pack_smallest fd_pack_smallest_t;
     170             : 
     171             : /* Forward declare opaque handle */
     172             : struct fd_pack_private;
     173             : typedef struct fd_pack_private fd_pack_t;
     174             : 
     175             : /* fd_pack_{align,footprint} return the required alignment and
     176             :    footprint in bytes for a region of memory to be used as a pack
     177             :    object.
     178             : 
     179             :    pack_depth sets the maximum number of pending transactions that pack
     180             :    stores and may eventually schedule.  pack_depth must be at least 4.
     181             : 
     182             :    If bundle_meta_sz is non-zero, then the bundle-related functions on
     183             :    this pack object can be used, and it can schedule bundles.
     184             :    Additionally, if bundle_meta_sz is non-zero, then a region of size
     185             :    bundle_meta_sz bytes (with no additional alignment) will be reserved
     186             :    for each bundle.
     187             : 
     188             :    Note: if you'd like to use bundles, but don't require metadata for
     189             :    the bundles, simply use a small positive value (e.g. 1), always pass
     190             :    NULL in insert_bundle_fini, and never call fd_pack_peek_bundle_meta.
     191             : 
     192             :    bank_tile_cnt sets the number of bank tiles to which this pack object
     193             :    can schedule transactions.  bank_tile_cnt must be in [1,
     194             :    FD_PACK_MAX_EXECLE_TILES].
     195             : 
     196             :    limits sets various limits for the blocks and microblocks that pack
     197             :    can produce. */
     198             : 
     199           0 : FD_FN_CONST static inline ulong fd_pack_align       ( void ) { return FD_PACK_ALIGN; }
     200             : 
     201             : FD_FN_PURE ulong
     202             : fd_pack_footprint( ulong                    pack_depth,
     203             :                    ulong                    bundle_meta_sz,
     204             :                    ulong                    bank_tile_cnt,
     205             :                    fd_pack_limits_t const * limits );
     206             : 
     207             : 
     208             : /* fd_pack_new formats a region of memory to be suitable for use as a
     209             :    pack object.  mem is a non-NULL pointer to a region of memory in the
     210             :    local address space with the required alignment and footprint.
     211             :    pack_depth, bundle_meta_sz, bank_tile_cnt, and limits are as above.
     212             :    The limits provided in this function are the maximum possible limits
     213             :    this pack object can handle without being completely reformatted.
     214             :    rng is a local join to a random number generator used to perturb
     215             :    estimates.  acct_blocklist is a list of accounts that cannot be read
     216             :    or written to.  acct_blocklist is accessed acct_blocklist[i] for i in
     217             :    [0, acct_blocklist_cnt).  acct_blocklist==NULL is okay if
     218             :    acct_blocklist_cnt==0.  acct_blocklist_cnt must be no more than
     219             :    FD_PACK_ACCT_BLOCKLIST_MAX.  acct_blocklist must not contain
     220             :    duplicates or the zero address.
     221             : 
     222             :    Returns `mem` (which will be properly formatted as a pack object) on
     223             :    success and NULL on failure.  Logs details on failure.  The caller
     224             :    will not be joined to the pack object when this function returns. */
     225             : void *
     226             : fd_pack_new( void                   * mem,
     227             :              ulong                    pack_depth,
     228             :              ulong                    bundle_meta_sz,
     229             :              ulong                    bank_tile_cnt,
     230             :              fd_pack_limits_t const * limits,
     231             :              fd_acct_addr_t const *   acct_blocklist,
     232             :              ulong                    acct_blocklist_cnt,
     233             :              fd_rng_t               * rng );
     234             : 
     235             : /* fd_pack_join joins the caller to the pack object.  Every successful
     236             :    join should have a matching leave.  Returns mem. */
     237             : fd_pack_t * fd_pack_join( void * mem );
     238             : 
     239             : 
     240             : /* fd_pack_avail_txn_cnt returns the number of transactions that this
     241             :    pack object has available to schedule but that have not been
     242             :    scheduled yet. pack must be a valid local join.  The return value
     243             :    will be in [0, pack_depth). */
     244             : 
     245             : /* For performance reasons, implement this here.  The offset is STATIC_ASSERTed
     246             :    in fd_pack.c. */
     247           0 : #define FD_PACK_PENDING_TXN_CNT_OFF 72
     248             : FD_FN_PURE static inline ulong
     249           0 : fd_pack_avail_txn_cnt( fd_pack_t const * pack ) {
     250           0 :   return *((ulong const *)((uchar const *)pack + FD_PACK_PENDING_TXN_CNT_OFF));
     251           0 : }
     252             : 
     253             : /* fd_pack_current_block_cost returns the number of CUs that have been
     254             :    scheduled in the current block, net of any rebates.  It should be
     255             :    between 0 and the specified value of max_cost_per_block, but it can
     256             :    be slightly higher due to temporary cost model nonsense.  Due to
     257             :    rebates, this number may decrease as the block progresses.  pack must
     258             :    be a valid local join. */
     259             : FD_FN_PURE ulong fd_pack_current_block_cost( fd_pack_t const * pack );
     260             : 
     261             : /* fd_pack_auction_begin starts an auction, which will last until
     262             :    fd_pack_auction_end is called.
     263             : 
     264             :    During the auction period, newly arrived transactions are not
     265             :    immediately scheduled, but instead held and can't be scheduled until
     266             :    the auction ends.  Newly arrived bundles are eligible for scheduling
     267             :    immediately.  Transactions that arrived before the auction started
     268             :    are eligible for scheduling throughout the auction.
     269             : 
     270             :    pack must be a valid local join. */
     271             : void             fd_pack_auction_begin       ( fd_pack_t *       pack );
     272             : 
     273             : /* fd_pack_auction_end ends the current auction, if there is one.  Any
     274             :    transactions that were held back during the auction now become
     275             :    eligible for scheduling.  pack must be a valid local join. */
     276             : void             fd_pack_auction_end         ( fd_pack_t *       pack );
     277             : 
     278             : /* fd_pack_auction_running returns 1 if an auction is currently running
     279             :    and 0 otherwise.  pack must be a valid local join. */
     280             : FD_FN_PURE int   fd_pack_auction_running     ( fd_pack_t const * pack );
     281             : 
     282             : /* fd_pack_next_auction_txn_cnt returns the number of transactions
     283             :    currently being held back until the current auction ends.  This will
     284             :    be 0 if no auction is running.  pack must be a valid local join. */
     285             : FD_FN_PURE ulong fd_pack_next_auction_txn_cnt( fd_pack_t const * pack );
     286             : 
     287             : /* fd_pack_bank_tile_cnt: returns the value of bank_tile_cnt provided in
     288             :    pack when the pack object was initialized with fd_pack_new.  pack
     289             :    must be a valid local join.  The result will be in [1,
     290             :    FD_PACK_MAX_EXECLE_TILES]. */
     291             : FD_FN_PURE ulong fd_pack_bank_tile_cnt( fd_pack_t const * pack );
     292             : 
     293             : /* fd_pack_set_block_limits: Updates the limits provided fd_pack_new to
     294             :    these new values.  Any future microblocks produced by this pack
     295             :    object will not cause a block to have more than
     296             :    limits->max_microblocks_per_block non-empty microblocks or more than
     297             :    limits->max_data_bytes_per_block data bytes (counting microblock
     298             :    headers as before).  future microblocks will also exclude those that
     299             :    cause the total block cost to exceed limits->max_cost_per_block.
     300             :    Also, those that cause the total
     301             :    per-account, per block write cost to exceed
     302             :    limits->max_write_cost_per_acct.  Note that
     303             :    limits->max_txn_per_microblock is ignored. Limits are inclusive, as
     304             :    per usual (i.e. a block may have exactly max_microblocks_per_block
     305             :    microblocks, but not more).  pack must be a valid local join.
     306             : 
     307             :    Limits used to size pack's storage must be no larger than those
     308             :    provided to fd_pack_new.  max_data_bytes_per_block does not size
     309             :    storage and may exceed its initial value.
     310             : 
     311             :    The typical place to call this is immediately after
     312             :    fd_pack_end_block; if this is called after some microblocks have been
     313             :    produced for the current block, and the current block already exceeds
     314             :    the limits, all the remaining microblocks in the block will be empty,
     315             :    but the call is valid. */
     316             : void fd_pack_set_block_limits( fd_pack_t * pack, fd_pack_limits_t const * limits );
     317             : 
     318             : /* fd_pack_get_block_limits: Copies the currently active pack limits
     319             :    into opt_limits, if opt_limits is not NULL.  Copies the current limit
     320             :    utilization in opt_limits_usage, if opt_limits_usage is not NULL.
     321             : 
     322             :    Limit utilization is updated both when each transactions is scheduled
     323             :    and when any used resources are rebated.
     324             : 
     325             :    The opt_limits_usage->top_writers field is ignored. */
     326             : void fd_pack_get_block_limits( fd_pack_t * pack, fd_pack_limits_usage_t * opt_limits_usage, fd_pack_limits_t * opt_limits );
     327             : 
     328             : /* fd_pack_get_top_writers copies the top FD_PACK_TOP_WRITERS_CNT by
     329             :    writer cost writers into top_writers.  The copied elements will be
     330             :    sorted by writer cost in descending order.
     331             : 
     332             :    This should be called at the end of the relevant leader slot right
     333             :    after fd_pack_end_block, otherwise the copied data will be stale. */
     334             : void fd_pack_get_top_writers( fd_pack_t const * pack, fd_pack_addr_use_t top_writers[static FD_PACK_TOP_WRITERS_CNT] );
     335             : 
     336             : /* Copies the currently smallest pending, non-conflicting, transaction
     337             :    into opt_pending_smallest iff it is not NULL.  This value is
     338             :    updated any time a new transaction is inserted into the pending
     339             :    treap, or moved from another treap into the pending treap. */
     340             : void fd_pack_get_pending_smallest( fd_pack_t * pack, fd_pack_smallest_t * opt_pending_smallest );
     341             : 
     342             : /* Return values for fd_pack_insert_txn_fini:  Non-negative values
     343             :    indicate the transaction was accepted and may be returned in a future
     344             :    microblock.  Negative values indicate that the transaction was
     345             :    rejected and will never be returned in a future microblock.
     346             :    Transactions can be rejected through no fault of their own, so it
     347             :    doesn't necessarily imply bad behavior.
     348             : 
     349             :    The non-negative (success) codes are essentially a bitflag of two
     350             :    bits:
     351             :     * (1) unused.  This bit was previously used to indicate that the
     352             :       transaction was a simple vote.
     353             :     * (2) whether this transaction replaced a previously accepted, low
     354             :       priority transaction, rather than being accepted in addition to
     355             :       all the previously accepted transactions.
     356             :     * (4) whether this transaction is a durable nonce transaction
     357             : 
     358             :    Since pack maintains a heap with a fixed max size of pack_depth,
     359             :    replacing transaction is necessary whenever the heap is full.
     360             :    Additionally, only one transaction with a given (nonce account, nonce
     361             :    authority, recent blockhash) value is allowed in pack's heap at a
     362             :    time, which means if there's already a lower priority transaction
     363             :    with the same nonce info, then this transaction will replace it.
     364             :    When the heap is full, and a nonce transaction is inserted, these
     365             :    return values don't allow you to disambiguate whether the replaced
     366             :    transaction had the same nonce info or not.
     367             : 
     368             :    The negative (failure) codes are a normal enumeration (not a
     369             :    bitflag).
     370             :     * PRIORITY: pack's heap was full and the transaction's priority was
     371             :       lower than the worst currently accepted transaction.
     372             :     * NONCE_PRIORITY: pack's heap had a transaction with the same
     373             :       durable nonce info that was higher priority.
     374             :     * DUPLICATE: the transaction is a duplicate of a currently accepted
     375             :       transaction.
     376             :     * UNAFFORDABLE: the fee payer could not afford the transaction fee
     377             :       (not yet implemented).
     378             :     * ADDR_LUT: the transaction tried to load an account from an address
     379             :       lookup table, which is not yet supported.
     380             :     * EXPIRED: the transaction was already expired upon insertion based
     381             :       on the provided value of expires_at compared to the last call to
     382             :       fd_pack_expire_before.
     383             :     * TOO_LARGE: the transaction requested too many CUs and would never
     384             :       be scheduled if it had been accepted.
     385             :     * ACCOUNT_CNT: the transaction tried to load more than 64 account
     386             :       addresses.
     387             :     * DUPLICATE_ACCT: the transaction included an account address twice
     388             :       in its list of account addresses to load.
     389             :     * ESTIMATION_FAIL: estimation of the transaction's compute cost and
     390             :       fee failed, typically because the transaction contained a
     391             :       malformed ComputeBudgetProgram instruction.
     392             :     * WRITES_SYSVAR: the transaction attempts to write-lock a sysvar.
     393             :       Write-locking a sysvar can cause heavy contention.  Agave
     394             :       solves this by downgrading these to read locks, but we instead
     395             :       solve it by refusing to pack such transactions.
     396             :     * INVALID_NONCE: the transaction looks like a durable nonce
     397             :       transaction, but the nonce authority did not sign the transaction.
     398             :     * BUNDLE_BLACKLIST: bundles are enabled and the transaction uses an
     399             :       account in the bundle blacklist.
     400             :     * ACCT_BLOCKLIST: the transaction included an account address in the
     401             :       account blocklist.
     402             :     * NONCE_CONFLICT: bundle with two transactions that attempt to lock
     403             :       the same durable nonce account and authority.
     404             :     * INSTR_ACCT_CNT: the transaction includes an instruction that
     405             :       references too many accounts.
     406             : 
     407             :     NOTE: The corresponding enum in metrics.xml must be kept in sync
     408             :     with any changes to these return values. */
     409             : #define FD_PACK_INSERT_ACCEPT_NONCE_NONVOTE_REPLACE (  6)
     410             : #define FD_PACK_INSERT_ACCEPT_NONCE_NONVOTE_ADD     (  4)
     411             : #define FD_PACK_INSERT_ACCEPT_NONVOTE_REPLACE       (  2)
     412             : #define FD_PACK_INSERT_ACCEPT_NONVOTE_ADD           (  0)
     413           0 : #define FD_PACK_INSERT_REJECT_PRIORITY              ( -1)
     414           0 : #define FD_PACK_INSERT_REJECT_NONCE_PRIORITY        ( -2)
     415             : #define FD_PACK_INSERT_REJECT_DUPLICATE             ( -3)
     416           0 : #define FD_PACK_INSERT_REJECT_UNAFFORDABLE          ( -4)
     417             : #define FD_PACK_INSERT_REJECT_ADDR_LUT              ( -5)
     418           0 : #define FD_PACK_INSERT_REJECT_EXPIRED               ( -6)
     419           0 : #define FD_PACK_INSERT_REJECT_TOO_LARGE             ( -7)
     420           0 : #define FD_PACK_INSERT_REJECT_ACCOUNT_CNT           ( -8)
     421           0 : #define FD_PACK_INSERT_REJECT_DUPLICATE_ACCT        ( -9)
     422           0 : #define FD_PACK_INSERT_REJECT_ESTIMATION_FAIL       (-10)
     423           0 : #define FD_PACK_INSERT_REJECT_WRITES_SYSVAR         (-11)
     424           0 : #define FD_PACK_INSERT_REJECT_INVALID_NONCE         (-12)
     425           0 : #define FD_PACK_INSERT_REJECT_BUNDLE_BLACKLIST      (-13)
     426           0 : #define FD_PACK_INSERT_REJECT_ACCT_BLOCKLIST        (-14)
     427           0 : #define FD_PACK_INSERT_REJECT_NONCE_CONFLICT        (-15)
     428             : #define FD_PACK_INSERT_REJECT_INSTR_ACCT_CNT        (-16)
     429             : 
     430             : /* The FD_PACK_INSERT_{ACCEPT, REJECT}_* values defined above are in the
     431             :    range [-FD_PACK_INSERT_RETVAL_OFF,
     432             :    -FD_PACK_INSERT_RETVAL_OFF+FD_PACK_INSERT_RETVAL_CNT ) */
     433           0 : #define FD_PACK_INSERT_RETVAL_OFF 16
     434           0 : #define FD_PACK_INSERT_RETVAL_CNT 23
     435             : 
     436             : FD_STATIC_ASSERT( FD_PACK_INSERT_REJECT_INSTR_ACCT_CNT>=-FD_PACK_INSERT_RETVAL_OFF, pack_retval );
     437             : FD_STATIC_ASSERT( FD_PACK_INSERT_ACCEPT_NONCE_NONVOTE_REPLACE<FD_PACK_INSERT_RETVAL_CNT-FD_PACK_INSERT_RETVAL_OFF, pack_retval );
     438             : 
     439             : /* fd_pack_insert_txn_{init,fini,cancel} execute the process of
     440             :    inserting a new transaction into the pool of available transactions
     441             :    that may be scheduled by the pack object.
     442             : 
     443             :    fd_pack_insert_txn_init returns a piece of memory from the txnmem
     444             :    region where the transaction should be stored.  The lifetime of this
     445             :    memory is managed by fd_pack as explained below.
     446             : 
     447             :    Every call to fd_pack_insert_init must be paired with a call to
     448             :    exactly one of _fini or _cancel.  Calling fd_pack_insert_txn_fini
     449             :    finalizes the transaction insert process and makes the newly-inserted
     450             :    transaction available for scheduling.  Calling
     451             :    fd_pack_insert_txn_cancel aborts the transaction insertion process.
     452             :    The txn pointer passed to _fini or _cancel must come from the most
     453             :    recent call to _init.
     454             : 
     455             :    The caller of these methods should not retain any read or write
     456             :    interest in the transaction after _fini or _cancel have been called.
     457             : 
     458             :    expires_at (for _fini only) bounds the lifetime of the inserted
     459             :    transaction.  No particular unit is prescribed, and it need not be
     460             :    higher than the previous call to txn_fini.  For durable nonce
     461             :    transactions and non-durable nonce transactions, it is interpreted
     462             :    somewhat differently.  For normal (non-durable nonce) transactions,
     463             :    if fd_pack_expire_before has been previously called with a value
     464             :    larger (strictly) than the provided expires_at, the transaction will
     465             :    be rejected with EXPIRED.  See fd_pack_expire_before for more
     466             :    details.  The Solana protocol doesn't subject durable nonce
     467             :    transactions to the same expiration process, however pack gives them
     468             :    a synthetic expires_at of FD_PACK_NONCE_SYNTHETIC_LIFETIME larger
     469             :    than largest value with which fd_pack_expire_before has been
     470             :    previously called.  Instead, the expires_at value for durable nonce
     471             :    transactions is primarily used as an ordering key: pack only keeps
     472             :    the transaction with the highest expires_at value for a given (nonce,
     473             :    nonce authority) tuple.
     474             : 
     475             :    pack must be a local join of a pack object.  From the caller's
     476             :    perspective, these functions cannot fail, though pack may reject a
     477             :    transaction for a variety of reasons.  fd_pack_insert_txn_fini
     478             :    returns one of the FD_PACK_INSERT_ACCEPT_* or FD_PACK_INSERT_REJECT_*
     479             :    codes explained above.
     480             :  */
     481             : fd_txn_e_t * fd_pack_insert_txn_init  ( fd_pack_t * pack                                                         );
     482             : int          fd_pack_insert_txn_fini  ( fd_pack_t * pack, fd_txn_e_t * txn, ulong expires_at, ulong * delete_cnt );
     483             : void         fd_pack_insert_txn_cancel( fd_pack_t * pack, fd_txn_e_t * txn                                       );
     484             : 
     485             : /* fd_pack_insert_bundle_{init,fini,cancel} are parallel to the
     486             :    similarly named fd_pack_insert_txn functions but can be used to
     487             :    insert a bundle instead of a transaction.
     488             : 
     489             :    fd_pack_insert_bundle_init populates and returns bundle.
     490             :    Specifically, it populates bundle[0], ...  bundle[txn_cnt-1] with
     491             :    pointers to fd_txn_p_t structs that should receive a new transaction.
     492             :    The pointers themselves should not be changed which is what the const
     493             :    indicates, but the contents of the fd_txn_p_t structs must be changed
     494             :    in order for this to be useful.  bundle must be a pointer to the
     495             :    first element of an array of at least txn_cnt pointers.
     496             : 
     497             :    The bundle consists of the transactions in the order they are
     498             :    provided.  I.e. bundle[0] will execute first in the bundle.
     499             : 
     500             :    Like with insert_txn, every call to fd_pack_insert_bundle_init must
     501             :    be paired with a call to exactly one of _fini or _cancel.  Calling
     502             :    fd_pack_insert_bundle_fini finalizes the bundle insertion process and
     503             :    makes the newly-inserted bundle available for scheduling.  Calling
     504             :    fd_pack_insert_bundle_cancel aborts the transaction insertion
     505             :    process.  There can be at most two outstanding bundles, of which one
     506             :    should be an initializer bundle.  The bundle argument passed to _fini
     507             :    or _cancel must be the return value of a call to _init with the same
     508             :    value of txn_cnt.  Additionally, it is okay to interleave calls to
     509             :    the insert_txn family of functions with calls to the insert_bundle
     510             :    family of functions.
     511             : 
     512             :    The caller of these methods should not retain any read or write
     513             :    interest in the fd_txn_p_t structs that the entries of bundle
     514             :    point to after _fini or _cancel have been called.
     515             : 
     516             :    expires_at has the same meaning as above.  Although transactions in
     517             :    the bundle may have different recent blockhashes, all transactions in
     518             :    the bundle have the same expires_at value, which should be that of
     519             :    the oldest, since if one expires, the whole bundle becomes invalid.
     520             :    The alternative interpretation of expires_at for durable nonce
     521             :    transactions means that they should be excluded in the calculation of
     522             :    the oldest.
     523             : 
     524             :    Bundles containing durable nonce transactions are always treated as
     525             :    having a newer nonce than any non-bundle transaction with the same
     526             :    (nonce account, authority) pair.  Within bundles, the older bundle is
     527             :    always treated as having a newer nonce (slightly counter-intuitively,
     528             :    but keeping in line with the bundle FIFO policy).
     529             : 
     530             :    If initializer_bundle is non-zero, this bundle will be inserted at
     531             :    the front of the bundle queue so that it is the next bundle
     532             :    scheduled.  Otherwise, the bundle will be inserted at the back of the
     533             :    bundle queue, and will be scheduled in FIFO order with the rest of
     534             :    the bundles.  If an initializer bundle is already present in pack's
     535             :    pending transactions, that bundle will be deleted.  Additionally, if
     536             :    initializer_bundle is non-zero, the transactions in the bundle will
     537             :    not be checked against the bundle blacklist; otherwise, the check
     538             :    will be performed as normal.  See the section below on initializer
     539             :    bundles for more details.
     540             : 
     541             :    Other than the blacklist check, transactions in a bundle are subject
     542             :    to the same checks as other transactions.  If any transaction in the
     543             :    bundle fails validation, the whole bundle will be rejected.
     544             : 
     545             :    _fini also accepts bundle_meta, an optional opaque pointer to a
     546             :    region of memory of size bundle_meta_sz (as provided in pack_new).
     547             :    If bundle_meta is non-NULL, the contents of the memory will be copied
     548             :    to a metadata region associated with this bundle and can be retrieved
     549             :    later with fd_pack_peek_bundle_meta.  The contents of bundle_meta is
     550             :    not retrievable if initializer_bundle is non-zero, so you may wish to
     551             :    just pass NULL in that case.  This function does not retain any
     552             :    interest in the contents of bundle_meta after it returns.
     553             : 
     554             :    txn_cnt must be in [1, MAX_TXN_PER_BUNDLE].  A txn_cnt of 1 inserts a
     555             :    single-transaction bundle which is transaction with extremely high
     556             :    priority.  That said, inserting transactions as bundles instead of
     557             :    transactions can hurt performance and throughput by introducing
     558             :    unnecessary stalls.
     559             : 
     560             :    fd_pack_insert_bundle_fini returns one of the FD_PACK_INSERT_ACCEPT_*
     561             :    or FD_PACK_INSERT_REJECT_* codes explained above.  If there are
     562             :    multiple reasons for rejecting a bundle, the which of the reasons it
     563             :    returns is unspecified.  delete_cnt is the number of existing
     564             :    transactions that were deleted as a side effect of insertion.
     565             : 
     566             :    These functions must not be called if the pack object was initialized
     567             :    with bundle_meta_sz==0. */
     568             : 
     569             : fd_txn_e_t * const * fd_pack_insert_bundle_init  ( fd_pack_t * pack, fd_txn_e_t *       * bundle, ulong txn_cnt                                        );
     570             : int                  fd_pack_insert_bundle_fini  ( fd_pack_t * pack, fd_txn_e_t * const * bundle, ulong txn_cnt,
     571             :                                                    ulong expires_at, int initializer_bundle, void const * bundle_meta, ulong * delete_cnt );
     572             : void                 fd_pack_insert_bundle_cancel( fd_pack_t * pack, fd_txn_e_t * const * bundle, ulong txn_cnt                                        );
     573             : 
     574             : 
     575             : /* =========== More details about initializer bundles ===============
     576             :    Initializer bundles are a special type of bundle with special support
     577             :    from the pack object to facilitate preparing on-chain state for the
     578             :    execution of bundles by this validator.  This design is a bit
     579             :    complicated, but it eliminates excessive coupling between pack and
     580             :    block engine details.
     581             : 
     582             :    The pack object maintains a small state machine (initializer bundle
     583             :    abbreviated IB):
     584             : 
     585             :       [Not Initialized]  ------------------------->|
     586             :           ^                                        | Schedule an
     587             :           |     End            Rebate shows        | IB
     588             :           |     block          IB failed           |
     589             :           |<----------[Failed]--------------|      v
     590             :           |                               --===[Pending]
     591             :           |<------------------------------/     ^  |
     592             :           |     End block                   /---|  |
     593             :           |                                 |      | Rebate shows
     594             :           |                        Schedule |      | IB succeeded
     595             :           |                      another IB |      |
     596             :           |     End block                   |      V
     597             :           -----------------------------------===[Ready]
     598             : 
     599             : 
     600             :    When attempting to schedule a bundle the pack object checks the
     601             :    state, and employs the following rules:
     602             :    * [Not Initialized]: If the top bundle is an IB, schedule it,
     603             :      removing it like normal, then transition to [Pending].  Otherwise,
     604             :      do not schedule a bundle.
     605             :    * [Pending]: Do not schedule a bundle.
     606             :    * [Failed]: Do not schedule a bundle
     607             :    * [Ready]: Attempt to schedule the next bundle.  If scheduling an IB,
     608             :      transition to [Pending].
     609             : 
     610             :    As described in the state machine, ending the block (via
     611             :    fd_pack_end_block) transitions to [Not Initialized], and calls to
     612             :    fd_pack_rebate_cus control the transition out of [Pending].
     613             : 
     614             :    This design supports a typical block engine system where some state
     615             :    may need to be initialized at the start of the slot and some state
     616             :    may need to change between runs of transactions (e.g. 5 transactions
     617             :    from block builder A followed by 5 transactions from block builder
     618             :    B).  This can be done by inserting an initializer bundle whenever the
     619             :    top non-initializer bundle's metadata state (retrievable with
     620             :    fd_pack_peek_bundle_meta) doesn't match the current on-chain state.
     621             :    Since the initializer bundle will execute before the bundle that was
     622             :    previously the top one, by the time the non-initializer bundle
     623             :    executes, the on-chain state will be correctly configured.  In this
     624             :    scheme, in the rare case that an initializer bundle was inserted but
     625             :    never executed, it should be deleted at the end of the slot.
     626             : 
     627             :    If at the start of the slot, it is determined that the on-chain state
     628             :    is in good shape, the state machine can transition directly to
     629             :    [Ready] by calling fd_pack_set_initializer_bundles_ready.
     630             : 
     631             :    Initializer bundles are not exempt from expiration, but it should not
     632             :    be a problem if they are always inserted with the most recent
     633             :    blockhash and deleted at the end of the slot.
     634             : 
     635             :    Additionally, a bundle marked as an IB is exempted from the bundle
     636             :    account blacklist checks.  For this reason, it's important that IB be
     637             :    generated by trusted code with minimal or sanitized
     638             :    attacker-controlled input. */
     639             : 
     640             : 
     641             : /* fd_pack_peek_bundle_meta returns a constant pointer to the bundle
     642             :    metadata associated with the bundle currently in line to be scheduled
     643             :    next, or NULL in any of the following cases:
     644             :      * There are no bundles
     645             :      * The bundle currently in line to be scheduled next is an IB
     646             :      * The bundle state is currently [Pending] or [Failed].
     647             : 
     648             :    The lifetime of the returned pointer is until the next pack insert,
     649             :    schedule, delete, or expire call.  The size of the region pointed to
     650             :    by the returned pointer is bundle_meta_sz.  If this bundle was
     651             :    inserted with bundle_meta==NULL, then the contents of the region
     652             :    pointed to by the returned pointer are arbitrary, but it will be safe
     653             :    to read.
     654             : 
     655             :    Pack doesn't do anything special to ensure the returned pointer
     656             :    points to memory with any particular alignment.  It will naturally
     657             :    have an alignment of at least GCD( 64, bundle_meta_sz ). */
     658             : void const * fd_pack_peek_bundle_meta( fd_pack_t const * pack );
     659             : 
     660             : /* fd_pack_set_initializer_bundles_ready sets the IB state machine state
     661             :    (see long initializer bundle comment above) to the [Ready] state.
     662             :    This function makes it easy to use bundles without initializer
     663             :    bundles.  pack must be a valid local join. */
     664             : void fd_pack_set_initializer_bundles_ready( fd_pack_t * pack );
     665             : 
     666             : /* fd_pack_set_rotation_end_ns informs pack of the wallclock time when
     667             :    the current leader rotation ends, in ns.  Bundles that arrive later
     668             :    than this are treated as pre-rotation bundles for the subsequent
     669             :    rotation. */
     670             : void fd_pack_set_rotation_end_ns( fd_pack_t * pack, long end_ns );
     671             : 
     672             : 
     673             : /* FD_PACK_SCHEDULE_{BUNDLE,TXN} form a set of bitflags used in
     674             :    fd_pack_schedule_next_microblock below.  They control what types of
     675             :    scheduling are allowed.  The names should be self-explanatory. */
     676           0 : #define FD_PACK_SCHEDULE_BUNDLE 2
     677           0 : #define FD_PACK_SCHEDULE_TXN    4
     678             : 
     679             : /* fd_pack_schedule_next_microblock schedules pending transactions.
     680             :    These transaction either form a microblock, which is a set of
     681             :    non-conflicting transactions, or a bundle.  The semantics of this
     682             :    function are a bit different depending on which one it picks, but
     683             :    there are some reasons why they both use this function.
     684             : 
     685             :    For both codepaths, pack must be a local join of a pack object.
     686             :    schedule_flags must be a bitwise combination of the
     687             :    FD_PACK_SCHEDULE_* values defined above.  When the bit is set
     688             :    corresponding to a transaction type, this function will consider
     689             :    scheduling transactions of that type.  Passing 0 for schedule_flags
     690             :    is a no-op.  The full policy is as follows:
     691             :     1. If the BUNDLE bit is set, attempt to schedule bundles.  This is
     692             :        the bundle case.
     693             :     2. If the TXN bit is set, and step 1 did not schedule any bundles
     694             :        for a reason other than account conflicts, attempt to schedule
     695             :        normal transactions.  This is the microblock case.
     696             :    Note that bundles cannot be combined with normal transactions.
     697             :    Additionally, if the BUNDLE bit is not set, step 1 will not schedule
     698             :    any bundles for that reason, which is a reason other than account
     699             :    conflicts, so that clause will always be satisfied.
     700             : 
     701             :    Microblock case:
     702             :    Transactions part of the scheduled microblock are copied to out in no
     703             :    particular order.  The cumulative cost of these transactions will not
     704             :    exceed total_cus, and the number of transactions will not exceed the
     705             :    value of max_txn_per_microblock given in fd_pack_new.
     706             : 
     707             :    Bundle case:
     708             :    Transactions part of the scheduled bundled are copied in execution
     709             :    order (i.e. out[0] must be executed first).  The number of
     710             :    transactions will not exceed FD_PACK_MAX_TXN_PER_BUNDLE.
     711             :    max_txn_per_microblock and total_cus are ignored, though the
     712             :    block-level limits are respected.
     713             : 
     714             :    Both cases:
     715             :    The non_execution_cus and requested_exec_plus_acct_data_cus fields of
     716             :    each transaction will be populated with the non execution CUs and
     717             :    requested execution CUs (including cus derived from the requested
     718             :    loaded accounts data size), respectively.  The sum of these two
     719             :    values is the total cost of the transaction, i.e. what is used for
     720             :    all limits, including the total_cus value.  The bundle and
     721             :    initializer bundle bits of the flags field will be populated.
     722             :    Inspecting these flags is the proper way to tell which codepath
     723             :    executed.
     724             : 
     725             :    Returns the number of transactions in the scheduled microblock or
     726             :    bundle.  The return value may be 0 if there are no eligible
     727             :    transactions at the moment. */
     728             : 
     729             : ulong
     730             : fd_pack_schedule_next_microblock( fd_pack_t  * pack,
     731             :                                   ulong        total_cus,
     732             :                                   ulong        bank_tile,
     733             :                                   int          schedule_flags,
     734             :                                   fd_txn_e_t * out );
     735             : 
     736             : 
     737             : /* fd_pack_rebate_cus adjusts the compute unit accounting for the
     738             :    specified transactions to take into account the actual consumed CUs
     739             :    after execution.  When a transaction is scheduled by
     740             :    schedule_next_microblock, pack assumes that it uses all the CUs it
     741             :    requests for the purposes of several CU limits.  If it doesn't use
     742             :    all the requested CUs, this function "rebates" them to pack so that
     743             :    they can be consumed by a different transaction in the block.
     744             : 
     745             :    pack must be a valid local join of a pack object.  rebate must point
     746             :    to a valid rebate report produced by fd_pack_rebate_sum_t.
     747             : 
     748             :    IMPORTANT: CU limits are reset at the end of each block, so this
     749             :    should not be called for transactions from a prior block.
     750             :    Specifically, there must not be a call to fd_pack_end_block between
     751             :    the call to schedule_next_microblock this is paired with and the call
     752             :    to rebate_cus.
     753             : 
     754             :    This function operates independently of microblock_complete.  In
     755             :    general, you probably need to call both.  microblock_complete must be
     756             :    called before scheduling another microblock to that bank tile, while
     757             :    rebate_cus is optional and has much more relaxed ordering
     758             :    constraints.  The restriction about intervening calls to end_block
     759             :    and that this must come after schedule_next_microblock are the only
     760             :    ordering constraints. */
     761             : void fd_pack_rebate_cus( fd_pack_t * pack, fd_pack_rebate_t const * rebate );
     762             : 
     763             : /* fd_pack_microblock_complete signals that the bank_tile with index
     764             :    bank_tile has completed its previously scheduled microblock.  This
     765             :    permits the scheduling of transactions that conflict with the
     766             :    previously scheduled microblock.  It is safe to call this multiple
     767             :    times after a microblock or even if bank_tile does not have a
     768             :    previously scheduled; in this case, the function will return 0 and
     769             :    act as a no-op.  Returns 1 if the bank_tile had an outstanding,
     770             :    previously scheduled microblock to mark as completed. */
     771             : int fd_pack_microblock_complete( fd_pack_t * pack, ulong bank_tile );
     772             : 
     773             : /* fd_pack_expire_before deletes all available transactions with
     774             :    expires_at values strictly less than expire_before.  For durable
     775             :    nonce transactions, this considers the synthetic expiration value as
     776             :    explained in insert_txn_fini.  pack must be a local join of a pack
     777             :    object.  Returns the number of transactions deleted.  Subsequent
     778             :    calls to fd_pack_expire_before with the same or a smaller value are
     779             :    no-ops. */
     780             : ulong fd_pack_expire_before( fd_pack_t * pack, ulong expire_before );
     781             : 
     782             : /* fd_pack_delete_txn removes a transaction (identified by its first
     783             :    signature) from the pool of available transactions.  Returns a
     784             :    nonzero count of the number of transactions deleted, if the
     785             :    transaction was found (and then removed) and 0 if not.  The count
     786             :    might be >1 if a bundle was caused to be deleted. */
     787             : ulong fd_pack_delete_transaction( fd_pack_t * pack, fd_ed25519_sig_t const * sig0 );
     788             : 
     789             : /* fd_pack_end_block resets some state to prepare for the next block.
     790             :    Specifically, the per-block limits are cleared and transactions in
     791             :    the microblocks scheduled after the call to this function are allowed
     792             :    to conflict with transactions in microblocks scheduled before the
     793             :    call to this function, even within gap microblocks. */
     794             : void fd_pack_end_block( fd_pack_t * pack );
     795             : 
     796             : 
     797             : /* fd_pack_clear_all resets the state associated with this pack object.
     798             :    All pending transactions are removed from the pool of available
     799             :    transactions and all limits are reset. */
     800             : void fd_pack_clear_all( fd_pack_t * pack );
     801             : 
     802             : 
     803             : /* fd_pack_metrics_write writes period metric values to the metrics
     804             :    system.  pack must be a valid local join. */
     805             : void
     806             : fd_pack_metrics_write( fd_pack_t const * pack );
     807             : 
     808             : /* fd_pack_get_sched_metrics: copies the current
     809             :    FD_METRICS_ENUM_PACK_TXN_SCHEDULE_RESULT_CNT counters to metrics */
     810             : void
     811             : fd_pack_get_sched_metrics( fd_pack_t const * pack, ulong * metrics );
     812             : 
     813             : /* fd_pack_leave leaves a local join of a pack object.  Returns pack. */
     814             : void * fd_pack_leave(  fd_pack_t * pack );
     815             : /* fd_pack_delete unformats a memory region used to store a pack object
     816             :    and returns ownership of the memory to the caller.  Returns mem. */
     817             : void * fd_pack_delete( void      * mem  );
     818             : 
     819             : /* fd_pack_verify (for debugging use primarily) checks to ensure several
     820             :    invariants are satisfied.  scratch must point to the first byte of a
     821             :    piece of memory meeting the same alignment and footprint constraints
     822             :    as pack.  Returns 0 on success and a negative value on failure
     823             :    (logging a warning with details). */
     824             : int fd_pack_verify( fd_pack_t * pack, void * scratch );
     825             : 
     826             : FD_PROTOTYPES_END
     827             : 
     828             : #endif /* HEADER_fd_src_disco_pack_fd_pack_h */

Generated by: LCOV version 1.14