LCOV - code coverage report
Current view: top level - ballet/pack - fd_pack.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 665 884 75.2 %
Date: 2024-11-13 11:58:15 Functions: 17 24 70.8 %

          Line data    Source code
       1             : #define FD_UNALIGNED_ACCESS_STYLE 0
       2             : #include "fd_pack.h"
       3             : #include "fd_pack_cost.h"
       4             : #include "fd_compute_budget_program.h"
       5             : #include "fd_pack_bitset.h"
       6             : #include "fd_chkdup.h"
       7             : #include "fd_pack_tip_prog_blacklist.h"
       8             : #include <math.h> /* for sqrt */
       9             : #include <stddef.h> /* for offsetof */
      10             : #include "../../disco/metrics/fd_metrics.h"
      11             : 
      12             : #define FD_PACK_USE_NON_TEMPORAL_MEMCPY 1
      13             : 
      14             : /* Declare a bunch of helper structs used for pack-internal data
      15             :    structures. */
      16             : 
      17             : /* fd_pack_ord_txn_t: An fd_txn_p_t with information required to order
      18             :    it by priority. */
      19             : struct fd_pack_private_ord_txn {
      20             :   /* It's important that there be no padding here (asserted below)
      21             :      because the code casts back and forth from pointers to this element
      22             :      to pointers to the whole struct. */
      23             :   union {
      24             :     fd_txn_p_t   txn[1];  /* txn is an alias for txn_e->txnp */
      25             :     fd_txn_e_t   txn_e[1];
      26             :   };
      27             : 
      28             :   /* Since this struct can be in one of several trees, it's helpful to
      29             :      store which tree.  This should be one of the FD_ORD_TXN_ROOT_*
      30             :      values. */
      31             :   int root;
      32             : 
      33             :   /* Each transaction is inserted with an expiration "time."  This code
      34             :      doesn't care about the units (blocks, rdtsc tick, ns, etc.), and
      35             :      doesn't require transactions to be inserted in expiration date
      36             :      order. */
      37             :   ulong expires_at;
      38             :   /* expq_idx: When this object is part of one of the treaps, it's
      39             :      also in the expiration priority queue.  This field (which is
      40             :      manipulated behind the scenes by the fd_prq code) stores where so
      41             :      that if we delete this transaction, we can also delete it from the
      42             :      expiration priority queue. */
      43             :   ulong expq_idx;
      44             : 
      45             :   /* We want rewards*compute_est to fit in a ulong so that r1/c1 < r2/c2 can be
      46             :      computed as r1*c2 < r2*c1, with the product fitting in a ulong.
      47             :      compute_est has a small natural limit of mid-20 bits. rewards doesn't have
      48             :      a natural limit, so there is some argument to be made for raising the
      49             :      limit for rewards to 40ish bits. The struct has better packing with
      50             :      uint/uint though. */
      51             :   uint                __attribute__((aligned(64))) /* We want the treap fields and the bitsets
      52             :                                                        to be on the same double cache line pair */
      53             :                rewards;     /* in Lamports */
      54             :   uint         compute_est; /* in compute units */
      55             : 
      56             :   /* The treap fields */
      57             :   ushort left;
      58             :   ushort right;
      59             :   ushort parent;
      60             :   ushort prio;
      61             :   ushort prev;
      62             :   ushort next;
      63             : 
      64             :   FD_PACK_BITSET_DECLARE( rw_bitset ); /* all accts this txn references */
      65             :   FD_PACK_BITSET_DECLARE(  w_bitset ); /* accts this txn write-locks    */
      66             : 
      67             : };
      68             : typedef struct fd_pack_private_ord_txn fd_pack_ord_txn_t;
      69             : 
      70             : /* What we want is that the payload starts at byte 0 of
      71             :    fd_pack_ord_txn_t so that the trick with the signature map works
      72             :    properly.  GCC and Clang seem to disagree on the rules of offsetof.
      73             :    */
      74             : FD_STATIC_ASSERT( offsetof( fd_pack_ord_txn_t, txn          )==0UL, fd_pack_ord_txn_t );
      75             : #if FD_USING_CLANG
      76             : FD_STATIC_ASSERT( offsetof( fd_txn_p_t,             payload )==0UL, fd_pack_ord_txn_t );
      77             : #else
      78             : FD_STATIC_ASSERT( offsetof( fd_pack_ord_txn_t, txn->payload )==0UL, fd_pack_ord_txn_t );
      79             : FD_STATIC_ASSERT( offsetof( fd_pack_ord_txn_t, txn_e->txnp  )==0UL, fd_pack_ord_txn_t );
      80             : #endif
      81             : 
      82           0 : #define FD_ORD_TXN_ROOT_FREE            0
      83    27110796 : #define FD_ORD_TXN_ROOT_PENDING         1
      84    13610346 : #define FD_ORD_TXN_ROOT_PENDING_VOTE    2
      85             : 
      86    28371678 : #define FD_PACK_IN_USE_WRITABLE    (0x8000000000000000UL)
      87    15346137 : #define FD_PACK_IN_USE_BIT_CLEARED (0x4000000000000000UL)
      88             : 
      89             : /* Each non-empty microblock we schedule also has an overhead of 48
      90             :    bytes that counts towards shed limits.  That comes from the 32 byte
      91             :    hash, the hash count (8 bytes) and the transaction count (8 bytes).
      92             :    We don't have to pay this overhead if the microblock is empty, since
      93             :    those microblocks get dropped. */
      94     1476432 : #define MICROBLOCK_DATA_OVERHEAD 48UL
      95             : 
      96             : /* Keep track of accounts that are written to in each block so that we
      97             :    can reset the writer costs to 0.  If the number of accounts that are
      98             :    written to is above or equal to this, we'll just clear the whole
      99             :    writer cost map instead of only removing the elements we increased. */
     100        1353 : #define DEFAULT_WRITTEN_LIST_MAX 16384UL
     101             : 
     102             : /* fd_pack_addr_use_t: Used for two distinct purposes:
     103             :     -  to record that an address is in use and can't be used again until
     104             :          certain microblocks finish execution
     105             :     -  to keep track of the cost of all transactions that write to the
     106             :          specified account.
     107             :    Making these separate structs might make it more clear, but then
     108             :    they'd have identical shape and result in two fd_map_dynamic sets of
     109             :    functions with identical code.  It doesn't seem like the compiler is
     110             :    very good at merging code like that, so in order to reduce code
     111             :    bloat, we'll just combine them. */
     112             : struct fd_pack_private_addr_use_record {
     113             :   fd_acct_addr_t key; /* account address */
     114             :   union {
     115             :     ulong          in_use_by;  /* Bitmask indicating which banks */
     116             :     ulong          total_cost; /* In cost units/CUs */
     117             :   };
     118             : };
     119             : typedef struct fd_pack_private_addr_use_record fd_pack_addr_use_t;
     120             : 
     121             : 
     122             : /* fd_pack_sig_to_entry_t: An element of an fd_map that maps the first
     123             :    transaction signature to the corresponding fd_pack_ord_txn_t so that
     124             :    pending transactions can be deleted by signature.  Note: this
     125             :    implicitly relies on the fact that for Solana transactions the
     126             :    signature_offset is always 1.  If that fact changes, this will need
     127             :    to become a real struct. */
     128             : struct fd_pack_sig_to_txn {
     129             :   fd_ed25519_sig_t const * key;
     130             : };
     131             : typedef struct fd_pack_sig_to_txn fd_pack_sig_to_txn_t;
     132             : 
     133             : /* fd_pack_expq_t: An element of an fd_prq to sort the transactions by
     134             :    timeout.  This structure has several invariants for entries
     135             :    corresponding to pending transactions:
     136             :      expires_at == txn->expires_at
     137             :      txn->exp_prq_idx is the index of this structure
     138             :    Notice that prq is an array-based heap, which means the indexes of
     139             :    elements change.  The PRQ_TMP_ST macro is hijacked to keep that
     140             :    invariant up to date.
     141             : 
     142             :    Note: this could be easier if fd_heap supported deleting from the
     143             :    middle, but that's not possible with the current design of fd_heap,
     144             :    which omits a parent pointer for improved performance. */
     145             : struct fd_pack_expq {
     146             :   ulong               expires_at;
     147             :   fd_pack_ord_txn_t * txn;
     148             : };
     149             : typedef struct fd_pack_expq fd_pack_expq_t;
     150             : 
     151             : 
     152             : /* fd_pack_bitset_acct_mapping_t: An element of an fd_map_dynamic that
     153             :    maps an account address to the number of transactions that are
     154             :    referencing it and the bit that is reserved to indicate it in the
     155             :    bitset, if any. */
     156             : struct fd_pack_bitset_acct_mapping {
     157             :   fd_acct_addr_t key; /* account address */
     158             :   ulong          ref_cnt;
     159             : 
     160             :   /* first_instance and first_instance_was_write are only valid when
     161             :      bit==FD_PACK_BITSET_FIRST_INSTANCE, which is set when ref_cnt
     162             :      transitions from 0 to 1.  These just exist to implement the
     163             :      optimization that accounts referenced a single time aren't
     164             :      allocated a bit, but this seems to be an important optimization. */
     165             :   fd_pack_ord_txn_t * first_instance;
     166             :   int                 first_instance_was_write;
     167             : 
     168             :   /* bit is in [0, FD_PACK_BITSET_MAX) U
     169             :      { FD_PACK_BITSET_FIRST_INSTANCE, FD_PACK_BITSET_SLOWPATH }. */
     170             :   ushort              bit;
     171             : };
     172             : typedef struct fd_pack_bitset_acct_mapping fd_pack_bitset_acct_mapping_t;
     173             : 
     174             : /* Table of special addresses that are not allowed to be written to.  We
     175             :    immediately reject and refuse to pack any transaction that tries to
     176             :    write to one of these accounts.  Because we reject any writes to any
     177             :    of these accounts, we actually don't need to track reads of them
     178             :    either.  This is nice, because fd_map_dynamic requires a null address
     179             :    that we promise never to insert.  The zero address is a sysvar, so
     180             :    now we meet that part of the fd_map_dynamic contract. */
     181             : #define MAP_PERFECT_NAME      fd_pack_unwritable
     182             : #define MAP_PERFECT_LG_TBL_SZ 5
     183             : #define MAP_PERFECT_T         fd_acct_addr_t
     184    25414101 : #define MAP_PERFECT_HASH_C    1402126759U
     185             : #define MAP_PERFECT_KEY       b
     186             : #define MAP_PERFECT_KEY_T     fd_acct_addr_t const *
     187             : #define MAP_PERFECT_ZERO_KEY  (0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0)
     188             : #define MAP_PERFECT_COMPLEX_KEY 1
     189    25414101 : #define MAP_PERFECT_KEYS_EQUAL(k1,k2) (!memcmp( (k1), (k2), 32UL ))
     190             : 
     191    25414101 : #define PERFECT_HASH( u ) (((MAP_PERFECT_HASH_C*(u))>>27)&0x1FU)
     192             : 
     193             : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
     194             :                              a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
     195             :                                           PERFECT_HASH( (a08 | (a09<<8) | (a10<<16) | (a11<<24)) )
     196    25414101 : #define MAP_PERFECT_HASH_R( ptr ) PERFECT_HASH( fd_uint_load_4( (uchar const *)ptr->b + 8UL ) )
     197             : 
     198             : /* This list is a superset of what Lab's is_builtin_key_or_sysvar checks. */
     199             : /* Sysvars */
     200             : #define MAP_PERFECT_0  ( SYSVAR_CLOCK_ID          ),
     201             : #define MAP_PERFECT_1  ( SYSVAR_EPOCH_SCHED_ID    ),
     202             : #define MAP_PERFECT_2  ( SYSVAR_FEES_ID           ),
     203             : #define MAP_PERFECT_3  ( SYSVAR_RECENT_BLKHASH_ID ),
     204             : #define MAP_PERFECT_4  ( SYSVAR_RENT_ID           ),
     205             : #define MAP_PERFECT_5  ( SYSVAR_REWARDS_ID        ),
     206             : #define MAP_PERFECT_6  ( SYSVAR_SLOT_HASHES_ID    ),
     207             : #define MAP_PERFECT_7  ( SYSVAR_SLOT_HIST_ID      ),
     208             : #define MAP_PERFECT_8  ( SYSVAR_STAKE_HIST_ID     ),
     209             : #define MAP_PERFECT_9  ( SYSVAR_INSTRUCTIONS_ID   ),
     210             : #define MAP_PERFECT_10 ( SYSVAR_EPOCH_REWARDS_ID  ),
     211             : #define MAP_PERFECT_11 ( SYSVAR_LAST_RESTART_ID   ),
     212             : /* Programs */
     213             : #define MAP_PERFECT_12 ( CONFIG_PROG_ID           ),
     214             : #define MAP_PERFECT_13 ( FEATURE_ID               ),
     215             : #define MAP_PERFECT_14 ( NATIVE_LOADER_ID         ),
     216             : #define MAP_PERFECT_15 ( STAKE_PROG_ID            ),
     217             : #define MAP_PERFECT_16 ( STAKE_CONFIG_PROG_ID     ),
     218             : #define MAP_PERFECT_17 ( VOTE_PROG_ID             ),
     219             : #define MAP_PERFECT_18 ( SYS_PROG_ID              ), /* Do not remove. See above. */
     220             : #define MAP_PERFECT_19 ( BPF_LOADER_1_PROG_ID     ),
     221             : #define MAP_PERFECT_20 ( BPF_LOADER_2_PROG_ID     ),
     222             : #define MAP_PERFECT_21 ( BPF_UPGRADEABLE_PROG_ID  ),
     223             : /* Extras */
     224             : #define MAP_PERFECT_22 ( ED25519_SV_PROG_ID       ),
     225             : #define MAP_PERFECT_23 ( KECCAK_SECP_PROG_ID      ),
     226             : #define MAP_PERFECT_24 ( COMPUTE_BUDGET_PROG_ID   ),
     227             : #define MAP_PERFECT_25 ( ADDR_LUT_PROG_ID         ),
     228             : #define MAP_PERFECT_26 ( NATIVE_MINT_ID           ),
     229             : #define MAP_PERFECT_27 ( TOKEN_PROG_ID            ),
     230             : #define MAP_PERFECT_28 ( SYSVAR_PROG_ID           ),
     231             : 
     232             : #include "../../util/tmpl/fd_map_perfect.c"
     233             : 
     234             : 
     235             : /* Returns 1 if x.rewards/x.compute < y.rewards/y.compute. Not robust. */
     236    86128137 : #define COMPARE_WORSE(x,y) ( ((ulong)((x)->rewards)*(ulong)((y)->compute_est)) < ((ulong)((y)->rewards)*(ulong)((x)->compute_est)) )
     237             : 
     238             : /* Declare all the data structures */
     239             : 
     240             : 
     241             : /* Define the big max-"heap" that we pull transactions off to schedule.
     242             :    The priority is given by reward/compute.  We may want to add in some
     243             :    additional terms at a later point.  In order to cheaply remove nodes,
     244             :    we actually use a treap.  */
     245             : #define POOL_NAME       trp_pool
     246        1566 : #define POOL_T          fd_pack_ord_txn_t
     247             : #define POOL_IDX_T      ushort
     248    29566221 : #define POOL_NEXT       parent
     249             : #include "../../util/tmpl/fd_pool.c"
     250             : 
     251             : #define TREAP_T         fd_pack_ord_txn_t
     252             : #define TREAP_NAME      treap
     253             : #define TREAP_QUERY_T   void *                                         /* We don't use query ... */
     254             : #define TREAP_CMP(a,b)  (__extension__({ (void)(a); (void)(b); -1; })) /* which means we don't need to give a real
     255             :                                                                           implementation to cmp either */
     256   170175306 : #define TREAP_IDX_T     ushort
     257             : #define TREAP_OPTIMIZE_ITERATION 1
     258    86128137 : #define TREAP_LT        COMPARE_WORSE
     259             : #include "../../util/tmpl/fd_treap.c"
     260             : 
     261             : 
     262             : /* Define a strange map where key and value are kind of the same
     263             :    variable.  Essentially, it maps the contents to which the pointer
     264             :    points to the value of the pointer. */
     265             : #define MAP_NAME              sig2txn
     266    39735195 : #define MAP_T                 fd_pack_sig_to_txn_t
     267   349774296 : #define MAP_KEY_T             fd_ed25519_sig_t const *
     268    19858191 : #define MAP_KEY_NULL          NULL
     269   349774296 : #define MAP_KEY_INVAL(k)      !(k)
     270             : #define MAP_MEMOIZE           0
     271   321622941 : #define MAP_KEY_EQUAL(k0,k1)  (((!!(k0))&(!!(k1)))&&(!memcmp((k0),(k1), FD_TXN_SIGNATURE_SZ)))
     272             : #define MAP_KEY_EQUAL_IS_SLOW 1
     273    41723961 : #define MAP_KEY_HASH(key)     fd_uint_load_4( (key) ) /* first 4 bytes of signature */
     274             : #include "../../util/tmpl/fd_map_dynamic.c"
     275             : 
     276             : 
     277             : static const fd_acct_addr_t null_addr = { 0 };
     278             : 
     279             : #define MAP_NAME              acct_uses
     280    93789201 : #define MAP_T                 fd_pack_addr_use_t
     281   110755050 : #define MAP_KEY_T             fd_acct_addr_t
     282   296306571 : #define MAP_KEY_NULL          null_addr
     283             : #if FD_HAS_AVX
     284   110755050 : # define MAP_KEY_INVAL(k)     _mm256_testz_si256( wb_ldu( (k).b ), wb_ldu( (k).b ) )
     285             : #else
     286             : # define MAP_KEY_INVAL(k)     MAP_KEY_EQUAL(k, null_addr)
     287             : #endif
     288    76808547 : #define MAP_KEY_EQUAL(k0,k1)  (!memcmp((k0).b,(k1).b, FD_TXN_ACCT_ADDR_SZ))
     289             : #define MAP_KEY_EQUAL_IS_SLOW 1
     290             : #define MAP_MEMOIZE           0
     291    93797715 : #define MAP_KEY_HASH(key)     ((uint)fd_ulong_hash( fd_ulong_load_8( (key).b ) ))
     292             : #include "../../util/tmpl/fd_map_dynamic.c"
     293             : 
     294             : 
     295             : #define MAP_NAME              bitset_map
     296    49841979 : #define MAP_T                 fd_pack_bitset_acct_mapping_t
     297    62658843 : #define MAP_KEY_T             fd_acct_addr_t
     298   871856457 : #define MAP_KEY_NULL          null_addr
     299             : #if FD_HAS_AVX
     300    62658843 : # define MAP_KEY_INVAL(k)     _mm256_testz_si256( wb_ldu( (k).b ), wb_ldu( (k).b ) )
     301             : #else
     302             : # define MAP_KEY_INVAL(k)     MAP_KEY_EQUAL(k, null_addr)
     303             : #endif
     304    37052535 : #define MAP_KEY_EQUAL(k0,k1)  (!memcmp((k0).b,(k1).b, FD_TXN_ACCT_ADDR_SZ))
     305             : #define MAP_KEY_EQUAL_IS_SLOW 1
     306             : #define MAP_MEMOIZE           0
     307    49866063 : #define MAP_KEY_HASH(key)     ((uint)fd_ulong_hash( fd_ulong_load_8( (key).b ) ))
     308             : #include "../../util/tmpl/fd_map_dynamic.c"
     309             : 
     310             : 
     311             : /* Since transactions can also expire, we also maintain a parallel
     312             :    priority queue.  This means elements are simultaneously part of the
     313             :    treap (ordered by priority) and the expiration queue (ordered by
     314             :    expiration).  It's tempting to use the priority field of the treap
     315             :    for this purpose, but that can result in degenerate treaps in some
     316             :    cases. */
     317             : #define PRQ_NAME             expq
     318    26781675 : #define PRQ_T                fd_pack_expq_t
     319    26146050 : #define PRQ_TIMEOUT_T        ulong
     320    26146050 : #define PRQ_TIMEOUT          expires_at
     321    13335402 : #define PRQ_TMP_ST(p,t)      do {                                   \
     322    13335402 :                                (p)[0] = (t);                        \
     323    13335402 :                                t.txn->expq_idx = (ulong)((p)-heap); \
     324    13335402 :                              } while( 0 )
     325             : #include "../../util/tmpl/fd_prq.c"
     326             : 
     327             : /* fd_pack_smallest: We want to keep track of the smallest transaction
     328             :    in each treap.  That way, if we know the amount of space left in the
     329             :    block is less than the smallest transaction in the heap, we can just
     330             :    skip the heap.  Since transactions can be deleted, etc. maintaining
     331             :    this precisely is hard, but we can maintain a conservative value
     332             :    fairly cheaply.  Since the CU limit or the byte limit can be the one
     333             :    that matters, we keep track of the smallest by both. */
     334             : struct fd_pack_smallest {
     335             :   ulong cus;
     336             :   ulong bytes;
     337             : };
     338             : typedef struct fd_pack_smallest fd_pack_smallest_t;
     339             : 
     340             : /* Finally, we can now declare the main pack data structure */
     341             : struct fd_pack_private {
     342             :   ulong      pack_depth;
     343             :   ulong      bank_tile_cnt;
     344             : 
     345             :   fd_pack_limits_t lim[1];
     346             : 
     347             :   ulong      pending_txn_cnt;
     348             :   ulong      microblock_cnt; /* How many microblocks have we
     349             :                                 generated in this block? */
     350             :   ulong      data_bytes_consumed; /* How much data is in this block so
     351             :                                      far ? */
     352             :   fd_rng_t * rng;
     353             : 
     354             :   ulong      cumulative_block_cost;
     355             :   ulong      cumulative_vote_cost;
     356             : 
     357             :   /* expire_before: Any transactions with expires_at strictly less than
     358             :      the current expire_before are removed from the available pending
     359             :      transaction.  Here, "expire" is used as a verb: cause all
     360             :      transactions before this time to expire. */
     361             :   ulong      expire_before;
     362             : 
     363             :   /* outstanding_microblock_mask: a bitmask indicating which banking
     364             :      tiles have outstanding microblocks, i.e. fd_pack has generated a
     365             :      microblock for that banking tile and the banking tile has not yet
     366             :      notified fd_pack that it has completed it. */
     367             :   ulong      outstanding_microblock_mask;
     368             : 
     369             :   /* The actual footprint for the pool and maps is allocated
     370             :      in the same order in which they are declared immediately following
     371             :      the struct.  I.e. these pointers point to memory not far after the
     372             :      struct.  The trees are just pointers into the pool so don't take up
     373             :      more space. */
     374             : 
     375             :   fd_pack_ord_txn_t * pool;
     376             : 
     377             :   /* Treaps (sorted by priority) of pending transactions.  We store the
     378             :      pending simple votes separately. */
     379             :   treap_t pending[1];
     380             :   treap_t pending_votes[1];
     381             : 
     382             :   /* pending{_votes}_smallest: keep a conservative estimate of the
     383             :      smallest transaction (by cost units and by bytes) in each heap.
     384             :      Both CUs and bytes should be set to ULONG_MAX is the treap is
     385             :      empty. */
     386             :   fd_pack_smallest_t pending_smallest[1];
     387             :   fd_pack_smallest_t pending_votes_smallest[1];
     388             : 
     389             :   /* expiration_q: At the same time that a transaction is in exactly one
     390             :      of the above treaps, it is also in the expiration queue, sorted by
     391             :      its expiration time.  This enables deleting all transactions that
     392             :      have expired, regardless of which treap they are in. */
     393             :   fd_pack_expq_t * expiration_q;
     394             : 
     395             :   /* acct_in_use: Map from account address to bitmask indicating which
     396             :      bank tiles are using the account and whether that use is read or
     397             :      write (msb). */
     398             :   fd_pack_addr_use_t   * acct_in_use;
     399             : 
     400             :   /* bitset_{w, rw}_in_use stores a subset of the information in
     401             :      acct_in_use using the compressed set format explained at the top of
     402             :      this file.  rw_in_use stores accounts in use for read or write
     403             :      while w_in_use stores only those in use for write. */
     404             :   FD_PACK_BITSET_DECLARE( bitset_rw_in_use );
     405             :   FD_PACK_BITSET_DECLARE( bitset_w_in_use  );
     406             : 
     407             :   /* writer_costs: Map from account addresses to the sum of costs of
     408             :      transactions that write to the account.  Used for enforcing limits
     409             :      on the max write cost per account per block. */
     410             :   fd_pack_addr_use_t   * writer_costs;
     411             : 
     412             :   /* At the end of every slot, we have to clear out writer_costs.  The
     413             :      map is large, but typically very sparsely populated.  As an
     414             :      optimization, we keep track of the elements of the map that we've
     415             :      actually used, up to a maximum.  If we use more than the maximum,
     416             :      we revert to the old way of just clearing the whole map.
     417             : 
     418             :      written_list indexed [0, written_list_cnt).
     419             :      written_list_cnt in  [0, written_list_max).
     420             : 
     421             :      written_list_cnt==written_list_max-1 means that the list may be
     422             :      incomplete and should be ignored. */
     423             :   fd_pack_addr_use_t * * written_list;
     424             :   ulong                  written_list_cnt;
     425             :   ulong                  written_list_max;
     426             : 
     427             : 
     428             :   fd_pack_sig_to_txn_t * signature_map; /* Stores pointers into pool for deleting by signature */
     429             : 
     430             :   /* use_by_bank: An array of size (max_txn_per_microblock *
     431             :      FD_TXN_ACCT_ADDR_MAX) for each banking tile.  Only the MSB of
     432             :      in_use_by is relevant.  Addressed use_by_bank[i][j] where i is in
     433             :      [0, bank_tile_cnt) and j is in [0, use_by_bank_cnt[i]).  Used
     434             :      mostly for clearing the proper bits of acct_in_use when a
     435             :      microblock finishes. */
     436             :   fd_pack_addr_use_t * use_by_bank    [ FD_PACK_MAX_BANK_TILES ];
     437             :   ulong                use_by_bank_cnt[ FD_PACK_MAX_BANK_TILES ];
     438             : 
     439             :   fd_histf_t txn_per_microblock [ 1 ];
     440             :   fd_histf_t vote_per_microblock[ 1 ];
     441             : 
     442             :   fd_histf_t scheduled_cus_per_block[ 1 ];
     443             :   fd_histf_t rebated_cus_per_block  [ 1 ];
     444             :   fd_histf_t net_cus_per_block      [ 1 ];
     445             :   ulong      cumulative_rebated_cus;
     446             : 
     447             :   /* use_bundles: if true (non-zero), allows the use of bundles, groups
     448             :      of transactions that are executed atomically with high priority */
     449             :   int        use_bundles;
     450             : 
     451             :   /* bitset_avail: a stack of which bits are not currently reserved and
     452             :      can be used to represent an account address.
     453             :      Indexed [0, bitset_avail_cnt].  Element 0 is fixed at
     454             :      FD_PACK_BITSET_SLOWPATH. */
     455             :   ushort bitset_avail[ 1UL+FD_PACK_BITSET_MAX ];
     456             :   ulong  bitset_avail_cnt;
     457             : 
     458             :   /* acct_to_bitset: an fd_map_dynamic that maps acct addresses to the
     459             :      reference count, which bit, etc. */
     460             :   fd_pack_bitset_acct_mapping_t * acct_to_bitset;
     461             : 
     462             :   /* chdkup: scratch memory chkdup needs for its internal processing */
     463             :   fd_chkdup_t chkdup[ 1 ];
     464             : };
     465             : 
     466             : typedef struct fd_pack_private fd_pack_t;
     467             : 
     468             : FD_STATIC_ASSERT( offsetof(fd_pack_t, pending_txn_cnt)==FD_PACK_PENDING_TXN_CNT_OFF, txn_cnt_off );
     469             : 
     470             : ulong
     471             : fd_pack_footprint( ulong                    pack_depth,
     472             :                    ulong                    bank_tile_cnt,
     473         309 :                    fd_pack_limits_t const * limits         ) {
     474         309 :   if( FD_UNLIKELY( (bank_tile_cnt==0) | (bank_tile_cnt>FD_PACK_MAX_BANK_TILES) ) ) return 0UL;
     475         309 :   if( FD_UNLIKELY( pack_depth<4UL ) ) return 0UL;
     476             : 
     477         309 :   ulong l;
     478         309 :   ulong max_acct_in_treap  = pack_depth * FD_TXN_ACCT_ADDR_MAX;
     479         309 :   ulong max_acct_in_flight = bank_tile_cnt * (FD_TXN_ACCT_ADDR_MAX * limits->max_txn_per_microblock + 1UL);
     480             : 
     481         309 :   ulong max_w_per_block    = fd_ulong_min( limits->max_cost_per_block / FD_PACK_COST_PER_WRITABLE_ACCT,
     482         309 :                                            limits->max_txn_per_microblock * limits->max_microblocks_per_block * FD_TXN_ACCT_ADDR_MAX );
     483         309 :   ulong written_list_max   = fd_ulong_min( max_w_per_block>>1, DEFAULT_WRITTEN_LIST_MAX );
     484             : 
     485             :   /* log base 2, but with a 2* so that the hash table stays sparse */
     486         309 :   int lg_uses_tbl_sz = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_flight ) );
     487         309 :   int lg_max_writers = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_w_per_block    ) );
     488         309 :   int lg_depth       = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*pack_depth         ) );
     489         309 :   int lg_acct_in_trp = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_treap  ) );
     490             : 
     491         309 :   l = FD_LAYOUT_INIT;
     492         309 :   l = FD_LAYOUT_APPEND( l, FD_PACK_ALIGN,      sizeof(fd_pack_t)                               );
     493         309 :   l = FD_LAYOUT_APPEND( l, trp_pool_align (),  trp_pool_footprint ( pack_depth+1UL           ) ); /* pool           */
     494         309 :   l = FD_LAYOUT_APPEND( l, expq_align     (),  expq_footprint     ( pack_depth+1UL           ) ); /* expiration prq */
     495         309 :   l = FD_LAYOUT_APPEND( l, acct_uses_align(),  acct_uses_footprint( lg_uses_tbl_sz           ) ); /* acct_in_use    */
     496         309 :   l = FD_LAYOUT_APPEND( l, acct_uses_align(),  acct_uses_footprint( lg_max_writers           ) ); /* writer_costs   */
     497         309 :   l = FD_LAYOUT_APPEND( l, 32UL,               sizeof(fd_pack_addr_use_t*)*written_list_max    ); /* written_list   */
     498         309 :   l = FD_LAYOUT_APPEND( l, sig2txn_align  (),  sig2txn_footprint  ( lg_depth                 ) ); /* signature_map  */
     499         309 :   l = FD_LAYOUT_APPEND( l, 32UL,               sizeof(fd_pack_addr_use_t)*max_acct_in_flight   ); /* use_by_bank    */
     500         309 :   l = FD_LAYOUT_APPEND( l, bitset_map_align(), bitset_map_footprint( lg_acct_in_trp          ) ); /* acct_to_bitset */
     501         309 :   return FD_LAYOUT_FINI( l, FD_PACK_ALIGN );
     502         309 : }
     503             : 
     504             : void *
     505             : fd_pack_new( void                   * mem,
     506             :              ulong                    pack_depth,
     507             :              ulong                    bank_tile_cnt,
     508             :              fd_pack_limits_t const * limits,
     509         522 :              fd_rng_t                * rng           ) {
     510             : 
     511         522 :   ulong max_acct_in_treap  = pack_depth * FD_TXN_ACCT_ADDR_MAX;
     512         522 :   ulong max_acct_in_flight = bank_tile_cnt * (FD_TXN_ACCT_ADDR_MAX * limits->max_txn_per_microblock + 1UL);
     513         522 :   ulong max_w_per_block    = fd_ulong_min( limits->max_cost_per_block / FD_PACK_COST_PER_WRITABLE_ACCT,
     514         522 :                                            limits->max_txn_per_microblock * limits->max_microblocks_per_block * FD_TXN_ACCT_ADDR_MAX );
     515         522 :   ulong written_list_max   = fd_ulong_min( max_w_per_block>>1, DEFAULT_WRITTEN_LIST_MAX );
     516             : 
     517             :   /* log base 2, but with a 2* so that the hash table stays sparse */
     518         522 :   int lg_uses_tbl_sz = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_flight ) );
     519         522 :   int lg_max_writers = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_w_per_block    ) );
     520         522 :   int lg_depth       = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*pack_depth         ) );
     521         522 :   int lg_acct_in_trp = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_treap  ) );
     522             : 
     523         522 :   FD_SCRATCH_ALLOC_INIT( l, mem );
     524         522 :   fd_pack_t * pack    = FD_SCRATCH_ALLOC_APPEND( l,  FD_PACK_ALIGN,       sizeof(fd_pack_t)                             );
     525             :   /* The pool has one extra element that is used between insert_init and
     526             :      cancel/fini. */
     527         522 :   void * _pool        = FD_SCRATCH_ALLOC_APPEND( l,  trp_pool_align(),    trp_pool_footprint ( pack_depth+1UL         ) );
     528         522 :   void * _expq        = FD_SCRATCH_ALLOC_APPEND( l,  expq_align(),        expq_footprint     ( pack_depth+1UL         ) );
     529         522 :   void * _uses        = FD_SCRATCH_ALLOC_APPEND( l,  acct_uses_align(),   acct_uses_footprint( lg_uses_tbl_sz         ) );
     530         522 :   void * _writer_cost = FD_SCRATCH_ALLOC_APPEND( l,  acct_uses_align(),   acct_uses_footprint( lg_max_writers         ) );
     531         522 :   void * _written_lst = FD_SCRATCH_ALLOC_APPEND( l,  32UL,                sizeof(fd_pack_addr_use_t*)*written_list_max  );
     532         522 :   void * _sig_map     = FD_SCRATCH_ALLOC_APPEND( l,  sig2txn_align(),     sig2txn_footprint  ( lg_depth               ) );
     533         522 :   void * _use_by_bank = FD_SCRATCH_ALLOC_APPEND( l,  32UL,                sizeof(fd_pack_addr_use_t)*max_acct_in_flight );
     534         522 :   void * _acct_bitset = FD_SCRATCH_ALLOC_APPEND( l,  bitset_map_align(),  bitset_map_footprint( lg_acct_in_trp        ) );
     535             : 
     536           0 :   pack->pack_depth                  = pack_depth;
     537         522 :   pack->bank_tile_cnt               = bank_tile_cnt;
     538         522 :   pack->lim[0]                      = *limits;
     539         522 :   pack->pending_txn_cnt             = 0UL;
     540         522 :   pack->microblock_cnt              = 0UL;
     541         522 :   pack->data_bytes_consumed         = 0UL;
     542         522 :   pack->rng                         = rng;
     543         522 :   pack->cumulative_block_cost       = 0UL;
     544         522 :   pack->cumulative_vote_cost        = 0UL;
     545         522 :   pack->expire_before               = 0UL;
     546         522 :   pack->outstanding_microblock_mask = 0UL;
     547         522 :   pack->cumulative_rebated_cus      = 0UL;
     548             : 
     549             : 
     550         522 :   trp_pool_new(  _pool,        pack_depth+1UL );
     551             : 
     552         522 :   fd_pack_ord_txn_t * pool = trp_pool_join( _pool );
     553         522 :   treap_seed( pool, pack_depth+1UL, fd_rng_ulong( rng ) );
     554         522 :   (void)trp_pool_leave( pool );
     555             : 
     556             : 
     557         522 :   treap_new( (void*)pack->pending,         pack_depth );
     558         522 :   treap_new( (void*)pack->pending_votes,   pack_depth );
     559             : 
     560         522 :   pack->pending_smallest->cus         = ULONG_MAX;
     561         522 :   pack->pending_smallest->bytes       = ULONG_MAX;
     562         522 :   pack->pending_votes_smallest->cus   = ULONG_MAX;
     563         522 :   pack->pending_votes_smallest->bytes = ULONG_MAX;
     564             : 
     565         522 :   expq_new( _expq, pack_depth+1UL );
     566             : 
     567         522 :   FD_PACK_BITSET_CLEAR( pack->bitset_rw_in_use );
     568         522 :   FD_PACK_BITSET_CLEAR( pack->bitset_w_in_use  );
     569             : 
     570         522 :   acct_uses_new( _uses,        lg_uses_tbl_sz );
     571         522 :   acct_uses_new( _writer_cost, lg_max_writers );
     572             : 
     573         522 :   pack->written_list     = _written_lst;
     574         522 :   pack->written_list_cnt = 0UL;
     575         522 :   pack->written_list_max = written_list_max;
     576             : 
     577         522 :   sig2txn_new(   _sig_map,     lg_depth       );
     578             : 
     579         522 :   fd_pack_addr_use_t * use_by_bank = (fd_pack_addr_use_t *)_use_by_bank;
     580        6771 :   for( ulong i=0UL; i<bank_tile_cnt; i++ ) pack->use_by_bank[i]=use_by_bank + i*(FD_TXN_ACCT_ADDR_MAX*limits->max_txn_per_microblock+1UL);
     581        6771 :   for( ulong i=0UL; i<bank_tile_cnt; i++ ) pack->use_by_bank_cnt[i]=0UL;
     582             : 
     583         522 :   fd_histf_new( pack->txn_per_microblock,  FD_MHIST_MIN( PACK, TOTAL_TRANSACTIONS_PER_MICROBLOCK_COUNT ),
     584         522 :                                            FD_MHIST_MAX( PACK, TOTAL_TRANSACTIONS_PER_MICROBLOCK_COUNT ) );
     585         522 :   fd_histf_new( pack->vote_per_microblock, FD_MHIST_MIN( PACK, VOTES_PER_MICROBLOCK_COUNT ),
     586         522 :                                            FD_MHIST_MAX( PACK, VOTES_PER_MICROBLOCK_COUNT ) );
     587             : 
     588         522 :   fd_histf_new( pack->scheduled_cus_per_block, FD_MHIST_MIN( PACK, CUS_SCHEDULED ),
     589         522 :                                                FD_MHIST_MAX( PACK, CUS_SCHEDULED ) );
     590         522 :   fd_histf_new( pack->rebated_cus_per_block,   FD_MHIST_MIN( PACK, CUS_REBATED   ),
     591         522 :                                                FD_MHIST_MAX( PACK, CUS_REBATED   ) );
     592         522 :   fd_histf_new( pack->net_cus_per_block,       FD_MHIST_MIN( PACK, CUS_NET       ),
     593         522 :                                                FD_MHIST_MAX( PACK, CUS_NET       ) );
     594             : 
     595         522 :   pack->use_bundles = 0;
     596             : 
     597         522 :   pack->bitset_avail[ 0 ] = FD_PACK_BITSET_SLOWPATH;
     598      178698 :   for( ulong i=0UL; i<FD_PACK_BITSET_MAX; i++ ) pack->bitset_avail[ i+1UL ] = (ushort)i;
     599         522 :   pack->bitset_avail_cnt = FD_PACK_BITSET_MAX;
     600             : 
     601         522 :   bitset_map_new( _acct_bitset, lg_acct_in_trp );
     602             : 
     603         522 :   fd_chkdup_new( pack->chkdup, rng );
     604             : 
     605         522 :   return mem;
     606         522 : }
     607             : 
     608             : fd_pack_t *
     609         522 : fd_pack_join( void * mem ) {
     610         522 :   FD_SCRATCH_ALLOC_INIT( l, mem );
     611         522 :   fd_pack_t * pack  = FD_SCRATCH_ALLOC_APPEND( l, FD_PACK_ALIGN, sizeof(fd_pack_t) );
     612             : 
     613           0 :   ulong pack_depth             = pack->pack_depth;
     614         522 :   ulong bank_tile_cnt          = pack->bank_tile_cnt;
     615             : 
     616         522 :   ulong max_acct_in_treap  = pack_depth * FD_TXN_ACCT_ADDR_MAX;
     617         522 :   ulong max_acct_in_flight = bank_tile_cnt * (FD_TXN_ACCT_ADDR_MAX * pack->lim->max_txn_per_microblock + 1UL);
     618         522 :   ulong max_w_per_block    = fd_ulong_min( pack->lim->max_cost_per_block / FD_PACK_COST_PER_WRITABLE_ACCT,
     619         522 :                                            pack->lim->max_txn_per_microblock * pack->lim->max_microblocks_per_block * FD_TXN_ACCT_ADDR_MAX );
     620         522 :   ulong written_list_max   = fd_ulong_min( max_w_per_block>>1, DEFAULT_WRITTEN_LIST_MAX );
     621             : 
     622         522 :   int lg_uses_tbl_sz = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_flight ) );
     623         522 :   int lg_max_writers = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_w_per_block    ) );
     624         522 :   int lg_depth       = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*pack_depth         ) );
     625         522 :   int lg_acct_in_trp = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_treap  ) );
     626             : 
     627             : 
     628         522 :   pack->pool          = trp_pool_join(   FD_SCRATCH_ALLOC_APPEND( l, trp_pool_align(),   trp_pool_footprint ( pack_depth+1UL ) ) );
     629         522 :   pack->expiration_q  = expq_join    (   FD_SCRATCH_ALLOC_APPEND( l, expq_align(),       expq_footprint     ( pack_depth+1UL ) ) );
     630         522 :   pack->acct_in_use   = acct_uses_join(  FD_SCRATCH_ALLOC_APPEND( l, acct_uses_align(),  acct_uses_footprint( lg_uses_tbl_sz ) ) );
     631         522 :   pack->writer_costs  = acct_uses_join(  FD_SCRATCH_ALLOC_APPEND( l, acct_uses_align(),  acct_uses_footprint( lg_max_writers ) ) );
     632         522 :   /* */                                  FD_SCRATCH_ALLOC_APPEND( l, 32UL,               sizeof(fd_pack_addr_use_t*)*written_list_max  );
     633         522 :   pack->signature_map = sig2txn_join(    FD_SCRATCH_ALLOC_APPEND( l, sig2txn_align(),    sig2txn_footprint  ( lg_depth       ) ) );
     634         522 :   /* */                                  FD_SCRATCH_ALLOC_APPEND( l, 32UL,               sizeof(fd_pack_addr_use_t)*max_acct_in_flight );
     635         522 :   pack->acct_to_bitset= bitset_map_join( FD_SCRATCH_ALLOC_APPEND( l, bitset_map_align(), bitset_map_footprint( lg_acct_in_trp) ) );
     636             : 
     637         522 :   FD_MGAUGE_SET( PACK, PENDING_TRANSACTIONS_HEAP_SIZE, pack_depth );
     638         522 :   return pack;
     639         522 : }
     640             : 
     641             : 
     642             : 
     643             : static int
     644             : fd_pack_estimate_rewards_and_compute( fd_txn_e_t        * txne,
     645    13572666 :                                       fd_pack_ord_txn_t * out ) {
     646    13572666 :   fd_txn_t * txn = TXN(txne->txnp);
     647    13572666 :   ulong sig_rewards = FD_PACK_FEE_PER_SIGNATURE * txn->signature_cnt; /* Easily in [5000, 635000] */
     648             : 
     649    13572666 :   ulong execution_cus;
     650    13572666 :   ulong adtl_rewards;
     651    13572666 :   ulong precompile_sigs;
     652    13572666 :   ulong cost = fd_pack_compute_cost( txn, txne->txnp->payload, &txne->txnp->flags, &execution_cus, &adtl_rewards, &precompile_sigs );
     653             : 
     654    13572666 :   if( FD_UNLIKELY( !cost ) ) return 0;
     655             : 
     656             :   /* precompile_sigs <= 16320, so after the addition,
     657             :      sig_rewards < 83,000,000 */
     658    13572663 :   sig_rewards += FD_PACK_FEE_PER_SIGNATURE * precompile_sigs;
     659             : 
     660             :   /* No fancy CU estimation in this version of pack
     661             :   for( ulong i=0UL; i<(ulong)txn->instr_cnt; i++ ) {
     662             :     uchar prog_id_idx = txn->instr[ i ].program_id;
     663             :     fd_acct_addr_t const * acct_addr = fd_txn_get_acct_addrs( txn, txnp->payload ) + (ulong)prog_id_idx;
     664             :   }
     665             :   */
     666    13572663 :   out->rewards                              = (adtl_rewards < (UINT_MAX - sig_rewards)) ? (uint)(sig_rewards + adtl_rewards) : UINT_MAX;
     667    13572663 :   out->compute_est                          = (uint)cost;
     668    13572663 :   out->txn->pack_cu.requested_execution_cus = (uint)execution_cus;
     669    13572663 :   out->txn->pack_cu.non_execution_cus       = (uint)(cost - execution_cus);
     670             : 
     671    13572663 :   out->root = (txne->txnp->flags & FD_TXN_P_FLAGS_IS_SIMPLE_VOTE) ? FD_ORD_TXN_ROOT_PENDING_VOTE : FD_ORD_TXN_ROOT_PENDING;
     672             : 
     673             : #if DETAILED_LOGGING
     674             :   FD_LOG_NOTICE(( "TXN estimated compute %lu+-%f. Rewards: %lu + %lu", compute_expected, (double)compute_variance, sig_rewards, adtl_rewards ));
     675             : #endif
     676             : 
     677    13572663 :   return 1;
     678    13572666 : }
     679             : 
     680             : /* Can the fee payer afford to pay a transaction with the specified
     681             :    price?  Returns 1 if so, 0 otherwise.  This is just a stub that
     682             :    always returns 1 for now.  In general, this function can't be totally
     683             :    accurate, because the transactions immediately prior to this one can
     684             :    affect the balance of this fee payer, but a simple check here may be
     685             :    helpful for reducing spam. */
     686             : static int
     687             : fd_pack_can_fee_payer_afford( fd_acct_addr_t const * acct_addr,
     688    13572663 :                               ulong                  price /* in lamports */) {
     689    13572663 :   (void)acct_addr;
     690    13572663 :   (void)price;
     691    13572663 :   return 1;
     692    13572663 : }
     693             : 
     694             : 
     695             : 
     696             : 
     697             : 
     698    13695066 : fd_txn_e_t * fd_pack_insert_txn_init(   fd_pack_t * pack                   ) { return trp_pool_ele_acquire( pack->pool )->txn_e; }
     699      122400 : void         fd_pack_insert_txn_cancel( fd_pack_t * pack, fd_txn_e_t * txn ) { trp_pool_ele_release( pack->pool, (fd_pack_ord_txn_t*)txn ); }
     700             : 
     701      491637 : #define REJECT( reason ) do {                                       \
     702      491637 :                            trp_pool_ele_release( pack->pool, ord ); \
     703      491637 :                            return FD_PACK_INSERT_REJECT_ ## reason; \
     704      491637 :                          } while( 0 )
     705             : 
     706    68152839 : #define ACCT_ITER_TO_PTR( iter ) (__extension__( {                                          \
     707    68152839 :       ulong __idx = fd_txn_acct_iter_idx( iter );                                           \
     708    68152839 :       fd_ptr_if( __idx<fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM ), accts, alt_adj )+__idx; \
     709    68152839 :       }))
     710             : 
     711             : int
     712             : fd_pack_insert_txn_fini( fd_pack_t  * pack,
     713             :                          fd_txn_e_t * txne,
     714    13572666 :                          ulong        expires_at ) {
     715             : 
     716    13572666 :   fd_pack_ord_txn_t * ord = (fd_pack_ord_txn_t *)txne;
     717             : 
     718    13572666 :   fd_txn_t * txn   = TXN(txne->txnp);
     719    13572666 :   uchar * payload  = txne->txnp->payload;
     720             : 
     721    13572666 :   fd_acct_addr_t const * accts   = fd_txn_get_acct_addrs( txn, payload );
     722             :   /* alt_adj is the pointer to the ALT expansion, adjusted so that if
     723             :      account address n is the first that comes from the ALT, it can be
     724             :      accessed with adj_lut[n]. */
     725    13572666 :   fd_acct_addr_t const * alt     = ord->txn_e->alt_accts;
     726    13572666 :   fd_acct_addr_t const * alt_adj = ord->txn_e->alt_accts - fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM );
     727    13572666 :   ulong imm_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM );
     728    13572666 :   ulong alt_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_ALT );
     729             : 
     730    13572666 :   if( FD_UNLIKELY( !fd_pack_estimate_rewards_and_compute( txne, ord ) ) ) REJECT( ESTIMATION_FAIL );
     731             : 
     732    13572663 :   ord->expires_at = expires_at;
     733    13572663 :   int is_vote = ord->root==FD_ORD_TXN_ROOT_PENDING_VOTE;
     734             : 
     735    13572663 :   int writes_to_sysvar = 0;
     736    13572663 :   for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
     737    28316622 :       iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
     738    14743959 :     writes_to_sysvar |= fd_pack_unwritable_contains( ACCT_ITER_TO_PTR( iter ) );
     739    14743959 :   }
     740             : 
     741    13572663 :   int bundle_blacklist = 0;
     742    13572663 :   if( FD_UNLIKELY( pack->use_bundles ) ) {
     743           0 :     for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_ALL );
     744           0 :         iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
     745           0 :       bundle_blacklist |= fd_pack_tip_prog_check_blacklist( ACCT_ITER_TO_PTR( iter ) );
     746           0 :     }
     747           0 :   }
     748             : 
     749    13572663 :   fd_ed25519_sig_t const * sig = fd_txn_get_signatures( txn, payload );
     750    13572663 :   fd_chkdup_t * chkdup = pack->chkdup;
     751             : 
     752             :   /* Throw out transactions ... */
     753             :   /*           ... that are unfunded */
     754    13572663 :   if( FD_UNLIKELY( !fd_pack_can_fee_payer_afford( accts, ord->rewards    ) ) ) REJECT( UNAFFORDABLE     );
     755             :   /*           ... that are so big they'll never run */
     756    13572663 :   if( FD_UNLIKELY( ord->compute_est >= pack->lim->max_cost_per_block       ) ) REJECT( TOO_LARGE        );
     757             :   /*           ... that load too many accounts (ignoring 9LZdXeKGeBV6hRLdxS1rHbHoEUsKqesCC2ZAPTPKJAbK) */
     758    13572663 :   if( FD_UNLIKELY( fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_ALL )>64UL     ) ) REJECT( ACCOUNT_CNT      );
     759             :   /*           ... that duplicate an account address */
     760    13572660 :   if( FD_UNLIKELY( fd_chkdup_check( chkdup, accts, imm_cnt, alt, alt_cnt ) ) ) REJECT( DUPLICATE_ACCT   );
     761             :   /*           ... that try to write to a sysvar */
     762    13572657 :   if( FD_UNLIKELY( writes_to_sysvar                                        ) ) REJECT( WRITES_SYSVAR    );
     763             :   /*           ... that we already know about */
     764    13572570 :   if( FD_UNLIKELY( sig2txn_query( pack->signature_map, sig, NULL         ) ) ) REJECT( DUPLICATE        );
     765             :   /*           ... that have already expired */
     766    13572567 :   if( FD_UNLIKELY( expires_at<pack->expire_before                          ) ) REJECT( EXPIRED          );
     767             :   /*           ... that use an account that violates bundle rules */
     768    13572555 :   if( FD_UNLIKELY( bundle_blacklist & 1                                    ) ) REJECT( BUNDLE_BLACKLIST );
     769             : 
     770             : 
     771    13572555 :   int replaces = 0;
     772    13572555 :   if( FD_UNLIKELY( pack->pending_txn_cnt == pack->pack_depth ) ) {
     773             :     /* If the tree is full, we want to see if this is better than the
     774             :        worst element in the treap before inserting.  If the new
     775             :        transaction is better than that one, we'll delete it and insert
     776             :        the new transaction. Otherwise, we'll throw away this
     777             :        transaction.  We want to make sure we provide reasonable quality
     778             :        of service for votes based on what fraction of the treap is votes
     779             :        though, so we'll employ the following policy:
     780             : 
     781             :          Case             New Vote                 New Non-vote
     782             :        Votes < 25%   Replace worst non-vote    If better, replace worst
     783             :                      with it                   non-vote with it
     784             : 
     785             :        Votes > 75%   If better, replace        Replace worst vote with
     786             :                      worst vote with it        it
     787             : 
     788             :        Else          If better, replace worse of worst non-vote and
     789             :                      worst vote                                        */
     790      494649 :     ulong vote_cnt     = treap_ele_cnt( pack->pending_votes ); int low_votes    = (vote_cnt    <(pack->pack_depth>>2));
     791      494649 :     ulong non_vote_cnt = treap_ele_cnt( pack->pending       ); int low_nonvotes = (non_vote_cnt<(pack->pack_depth>>2));
     792      494649 :     int pool_imbalanced = low_votes | low_nonvotes;
     793      494649 :     int improves_balance = (low_votes & is_vote) | (low_nonvotes & !is_vote);
     794             : 
     795             :     /* Need to check that corresponding treap was not empty before dereferencing
     796             :        these two pointers. */
     797      494649 :     fd_pack_ord_txn_t * worst_vote    = treap_fwd_iter_ele( treap_fwd_iter_init( pack->pending_votes, pack->pool ), pack->pool );
     798      494649 :     fd_pack_ord_txn_t * worst_nonvote = treap_fwd_iter_ele( treap_fwd_iter_init( pack->pending,       pack->pool ), pack->pool );
     799      494649 :     fd_pack_ord_txn_t * worst = NULL;
     800             : 
     801             :     /* In the imbalanced case, there are two symmetric cases.
     802             :        Considering just the first one, low_nonvotes==true implies
     803             :              vote_cnt > pack_depth - (pack_depth>>2)
     804             :        Which means vote_cnt>0.  In the imbalanced case when
     805             :        low_nonvotes==false, we know low_votes must be true, so similar
     806             :        logic applies.
     807             :        In the balanced case, vote_cnt and non_vote_cnt are both at least
     808             :        as large as (pack_depth>>2) >= 1, since pack_depth>=4 so
     809             :        worst_vote and worst_nonvote are safe, implying worst is safe. */
     810      494649 :     if( pool_imbalanced ) worst = fd_ptr_if( low_nonvotes,                               worst_vote, worst_nonvote );
     811          42 :     else                  worst = fd_ptr_if( COMPARE_WORSE( worst_vote, worst_nonvote ), worst_vote, worst_nonvote );
     812             : 
     813      494649 :     if( FD_LIKELY( improves_balance || COMPARE_WORSE( worst, ord ) ) ) {
     814        3123 :       replaces = 1;
     815        3123 :       fd_ed25519_sig_t const * worst_sig = fd_txn_get_signatures( TXN( worst->txn ), worst->txn->payload );
     816        3123 :       fd_pack_delete_transaction( pack, worst_sig );
     817      491526 :     } else {
     818      491526 :       REJECT( PRIORITY );
     819      491526 :     }
     820      494649 :   }
     821             : 
     822             :   /* At this point, we know we have space to insert the transaction and
     823             :      we've committed to insert it. */
     824             : 
     825    13081029 :   FD_PACK_BITSET_CLEAR( ord->rw_bitset );
     826    13081029 :   FD_PACK_BITSET_CLEAR( ord->w_bitset  );
     827             : 
     828    13081029 :   for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
     829    27333174 :       iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
     830    14252145 :     fd_acct_addr_t acct = *ACCT_ITER_TO_PTR( iter );
     831    14252145 :     fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, acct, NULL );
     832    14252145 :     if( FD_UNLIKELY( q==NULL ) ) {
     833    12767358 :       q = bitset_map_insert( pack->acct_to_bitset, acct );
     834    12767358 :       q->ref_cnt                  = 0UL;
     835    12767358 :       q->first_instance           = ord;
     836    12767358 :       q->first_instance_was_write = 1;
     837    12767358 :       q->bit                      = FD_PACK_BITSET_FIRST_INSTANCE;
     838    12767358 :     } else if( FD_UNLIKELY( q->bit == FD_PACK_BITSET_FIRST_INSTANCE ) ) {
     839        5982 :       q->bit = pack->bitset_avail[ pack->bitset_avail_cnt ];
     840        5982 :       pack->bitset_avail_cnt = fd_ulong_if( !!pack->bitset_avail_cnt, pack->bitset_avail_cnt-1UL, 0UL );
     841             : 
     842        5982 :       FD_PACK_BITSET_SETN( q->first_instance->rw_bitset, q->bit );
     843        5982 :       if( q->first_instance_was_write ) FD_PACK_BITSET_SETN( q->first_instance->w_bitset, q->bit );
     844        5982 :     }
     845             : 
     846    14252145 :     q->ref_cnt++;
     847    14252145 :     FD_PACK_BITSET_SETN( ord->rw_bitset, q->bit );
     848    14252145 :     FD_PACK_BITSET_SETN( ord->w_bitset , q->bit );
     849    14252145 :   }
     850             : 
     851    13081029 :   for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY );
     852    16643970 :       iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
     853             : 
     854     3562941 :     fd_acct_addr_t acct = *ACCT_ITER_TO_PTR( iter );
     855     3562941 :     if( FD_UNLIKELY( fd_pack_unwritable_contains( &acct ) ) ) continue;
     856             : 
     857     2571744 :     fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, acct, NULL );
     858     2571744 :     if( FD_UNLIKELY( q==NULL ) ) {
     859       23733 :       q = bitset_map_insert( pack->acct_to_bitset, acct );
     860       23733 :       q->ref_cnt                  = 0UL;
     861       23733 :       q->first_instance           = ord;
     862       23733 :       q->first_instance_was_write = 0;
     863       23733 :       q->bit                      = FD_PACK_BITSET_FIRST_INSTANCE;
     864     2548011 :     } else if( FD_UNLIKELY( q->bit == FD_PACK_BITSET_FIRST_INSTANCE ) ) {
     865       10638 :       q->bit = pack->bitset_avail[ pack->bitset_avail_cnt ];
     866       10638 :       pack->bitset_avail_cnt = fd_ulong_if( !!pack->bitset_avail_cnt, pack->bitset_avail_cnt-1UL, 0UL );
     867             : 
     868       10638 :       FD_PACK_BITSET_SETN( q->first_instance->rw_bitset, q->bit );
     869       10638 :       if( q->first_instance_was_write ) FD_PACK_BITSET_SETN( q->first_instance->w_bitset, q->bit );
     870       10638 :     }
     871             : 
     872     2571744 :     q->ref_cnt++;
     873     2571744 :     FD_PACK_BITSET_SETN( ord->rw_bitset, q->bit );
     874     2571744 :   }
     875             : 
     876    13081029 :   pack->pending_txn_cnt++;
     877             : 
     878    13081029 :   sig2txn_insert( pack->signature_map, fd_txn_get_signatures( txn, payload ) );
     879             : 
     880    13081029 :   fd_pack_expq_t temp[ 1 ] = {{ .expires_at = expires_at, .txn = ord }};
     881    13081029 :   expq_insert( pack->expiration_q, temp );
     882             : 
     883    13081029 :   fd_pack_smallest_t * smallest = fd_ptr_if( is_vote, &pack->pending_votes_smallest[0], pack->pending_smallest );
     884    13081029 :   smallest->cus   = fd_ulong_min( smallest->cus,   ord->compute_est       );
     885    13081029 :   smallest->bytes = fd_ulong_min( smallest->bytes, txne->txnp->payload_sz );
     886             : 
     887    13081029 :   if( FD_LIKELY( is_vote ) ) {
     888       37644 :     treap_ele_insert( pack->pending_votes, ord, pack->pool );
     889       37644 :     return replaces ? FD_PACK_INSERT_ACCEPT_VOTE_REPLACE : FD_PACK_INSERT_ACCEPT_VOTE_ADD;
     890    13043385 :   } else {
     891    13043385 :     treap_ele_insert( pack->pending,       ord, pack->pool );
     892    13043385 :     return replaces ? FD_PACK_INSERT_ACCEPT_NONVOTE_REPLACE : FD_PACK_INSERT_ACCEPT_NONVOTE_ADD;
     893    13043385 :   }
     894    13081029 : }
     895             : #undef REJECT
     896             : 
     897             : void
     898           0 : fd_pack_metrics_write( fd_pack_t const * pack ) {
     899           0 :   FD_MGAUGE_SET( PACK, AVAILABLE_TRANSACTIONS,      pack->pending_txn_cnt                );
     900           0 :   FD_MGAUGE_SET( PACK, AVAILABLE_VOTE_TRANSACTIONS, treap_ele_cnt( pack->pending_votes ) );
     901           0 : }
     902             : 
     903             : typedef struct {
     904             :   ushort clear_rw_bit;
     905             :   ushort clear_w_bit;
     906             : } release_result_t;
     907             : 
     908             : static inline release_result_t
     909             : release_bit_reference( fd_pack_t            * pack,
     910    16822779 :                        fd_acct_addr_t const * acct ) {
     911             : 
     912    16822779 :   fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, *acct, NULL );
     913    16822779 :   FD_TEST( q ); /* q==NULL not be possible */
     914             : 
     915    16822779 :   q->ref_cnt--;
     916             : 
     917    16822779 :   if( FD_UNLIKELY( q->ref_cnt==0UL ) ) {
     918    12790089 :     ushort bit = q->bit;
     919    12790089 :     bitset_map_remove( pack->acct_to_bitset, q );
     920    12790089 :     if( FD_LIKELY( bit<FD_PACK_BITSET_MAX ) ) pack->bitset_avail[ ++(pack->bitset_avail_cnt) ] = bit;
     921             : 
     922    12790089 :     fd_pack_addr_use_t * use = acct_uses_query( pack->acct_in_use,  *acct, NULL );
     923    12790089 :     if( FD_LIKELY( use ) ) {
     924    12786849 :       use->in_use_by |= FD_PACK_IN_USE_BIT_CLEARED;
     925    12786849 :       release_result_t ret = { .clear_rw_bit = bit,
     926    12786849 :                                .clear_w_bit = fd_ushort_if( !!(use->in_use_by & FD_PACK_IN_USE_WRITABLE), bit, FD_PACK_BITSET_MAX ) };
     927    12786849 :       return ret;
     928    12786849 :     }
     929    12790089 :   }
     930     4035930 :   release_result_t ret = { .clear_rw_bit = FD_PACK_BITSET_MAX, .clear_w_bit = FD_PACK_BITSET_MAX };
     931     4035930 :   return ret;
     932    16822779 : }
     933             : 
     934             : typedef struct {
     935             :   ulong cus_scheduled;
     936             :   ulong txns_scheduled;
     937             :   ulong bytes_scheduled;
     938             : } sched_return_t;
     939             : 
     940             : static inline sched_return_t
     941             : fd_pack_schedule_impl( fd_pack_t          * pack,
     942             :                        treap_t            * sched_from,
     943             :                        ulong                cu_limit,
     944             :                        ulong                txn_limit,
     945             :                        ulong                byte_limit,
     946             :                        ulong                bank_tile,
     947             :                        fd_pack_smallest_t * smallest_in_treap,
     948     2214648 :                        fd_txn_p_t         * out ) {
     949             : 
     950     2214648 :   fd_pack_ord_txn_t  * pool         = pack->pool;
     951     2214648 :   fd_pack_addr_use_t * acct_in_use  = pack->acct_in_use;
     952     2214648 :   fd_pack_addr_use_t * writer_costs = pack->writer_costs;
     953             : 
     954     2214648 :   fd_pack_addr_use_t ** written_list     = pack->written_list;
     955     2214648 :   ulong                 written_list_cnt = pack->written_list_cnt;
     956     2214648 :   ulong                 written_list_max = pack->written_list_max;
     957             : 
     958     2214648 :   FD_PACK_BITSET_DECLARE( bitset_rw_in_use );
     959     2214648 :   FD_PACK_BITSET_DECLARE( bitset_w_in_use  );
     960     2214648 :   FD_PACK_BITSET_COPY( bitset_rw_in_use, pack->bitset_rw_in_use );
     961     2214648 :   FD_PACK_BITSET_COPY( bitset_w_in_use,  pack->bitset_w_in_use  );
     962             : 
     963     2214648 :   fd_pack_addr_use_t * use_by_bank     = pack->use_by_bank    [bank_tile];
     964     2214648 :   ulong                use_by_bank_cnt = pack->use_by_bank_cnt[bank_tile];
     965             : 
     966     2214648 :   ulong max_write_cost_per_acct = pack->lim->max_write_cost_per_acct;
     967             : 
     968     2214648 :   ulong txns_scheduled  = 0UL;
     969     2214648 :   ulong cus_scheduled   = 0UL;
     970     2214648 :   ulong bytes_scheduled = 0UL;
     971             : 
     972     2214648 :   ulong bank_tile_mask = 1UL << bank_tile;
     973             : 
     974     2214648 :   ulong fast_path     = 0UL;
     975     2214648 :   ulong slow_path     = 0UL;
     976     2214648 :   ulong cu_limit_c    = 0UL;
     977     2214648 :   ulong byte_limit_c  = 0UL;
     978     2214648 :   ulong write_limit_c = 0UL;
     979             : 
     980     2214648 :   ulong min_cus   = ULONG_MAX;
     981     2214648 :   ulong min_bytes = ULONG_MAX;
     982             : 
     983     2214648 :   if( FD_UNLIKELY( (cu_limit<smallest_in_treap->cus) | (txn_limit==0UL) | (byte_limit<smallest_in_treap->bytes) ) ) {
     984     1454805 :     sched_return_t to_return = { .cus_scheduled = 0UL, .txns_scheduled = 0UL, .bytes_scheduled = 0UL };
     985     1454805 :     return to_return;
     986     1454805 :   }
     987             : 
     988      759843 :   treap_rev_iter_t prev = treap_idx_null();
     989   121100577 :   for( treap_rev_iter_t _cur=treap_rev_iter_init( sched_from, pool ); !treap_rev_iter_done( _cur ); _cur=prev ) {
     990             :     /* Capture next so that we can delete while we iterate. */
     991   120934905 :     prev = treap_rev_iter_next( _cur, pool );
     992             : 
     993   120934905 : #   if FD_HAS_X86
     994   120934905 :     _mm_prefetch( &(pool[ prev ].prev),      _MM_HINT_T0 );
     995   120934905 : #   endif
     996             : 
     997   120934905 :     fd_pack_ord_txn_t const * cur = treap_rev_iter_ele_const( _cur, pool );
     998             : 
     999   120934905 :     min_cus   = fd_ulong_min( min_cus,   cur->compute_est     );
    1000   120934905 :     min_bytes = fd_ulong_min( min_bytes, cur->txn->payload_sz );
    1001             : 
    1002   120934905 :     ulong conflicts = 0UL;
    1003             : 
    1004   120934905 :     if( FD_UNLIKELY( cur->compute_est>cu_limit ) ) {
    1005             :       /* Too big to be scheduled at the moment, but might be okay for
    1006             :          the next microblock, so we don't want to delay it. */
    1007           0 :       cu_limit_c++;
    1008           0 :       continue;
    1009           0 :     }
    1010             : 
    1011             :     /* Likely? Unlikely? */
    1012   120934905 :     if( FD_LIKELY( !FD_PACK_BITSET_INTERSECT4_EMPTY( bitset_rw_in_use, bitset_w_in_use, cur->w_bitset, cur->rw_bitset ) ) ) {
    1013   107857518 :       fast_path++;
    1014   107857518 :       continue;
    1015   107857518 :     }
    1016             : 
    1017    13077387 :     if( FD_UNLIKELY( cur->txn->payload_sz>byte_limit ) ) {
    1018           0 :       byte_limit_c++;
    1019           0 :       continue;
    1020           0 :     }
    1021             : 
    1022    13077387 :     fd_txn_t const * txn = TXN(cur->txn);
    1023    13077387 :     fd_acct_addr_t const * accts   = fd_txn_get_acct_addrs( txn, cur->txn->payload );
    1024    13077387 :     fd_acct_addr_t const * alt_adj = cur->txn_e->alt_accts - fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM );
    1025             :     /* Check conflicts between this transaction's writable accounts and
    1026             :        current readers */
    1027    13077387 :     for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
    1028    27316080 :         iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1029             : 
    1030    14238705 :       fd_acct_addr_t acct = *ACCT_ITER_TO_PTR( iter );
    1031             : 
    1032    14238705 :       fd_pack_addr_use_t * in_wcost_table = acct_uses_query( writer_costs, acct, NULL );
    1033    14238705 :       if( FD_UNLIKELY( in_wcost_table && in_wcost_table->total_cost+cur->compute_est > max_write_cost_per_acct ) ) {
    1034             :         /* Can't be scheduled until the next block */
    1035          12 :         conflicts = ULONG_MAX;
    1036          12 :         break;
    1037          12 :       }
    1038             : 
    1039    14238693 :       fd_pack_addr_use_t * use = acct_uses_query( acct_in_use, acct, NULL );
    1040    14238693 :       if( FD_UNLIKELY( use ) ) conflicts |= use->in_use_by; /* break? */
    1041    14238693 :     }
    1042             : 
    1043    13077387 :     if( FD_UNLIKELY( conflicts==ULONG_MAX ) ) {
    1044          12 :       write_limit_c++;
    1045          12 :       continue;
    1046          12 :     }
    1047             : 
    1048    13077375 :     if( FD_UNLIKELY( conflicts ) ) {
    1049          12 :       slow_path++;
    1050          12 :       continue;
    1051          12 :     }
    1052             : 
    1053             :     /* Check conflicts between this transaction's readonly accounts and
    1054             :        current writers */
    1055    13077363 :     for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY );
    1056    16623162 :         iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1057             : 
    1058     3545799 :       fd_acct_addr_t const * acct = ACCT_ITER_TO_PTR( iter );
    1059     3545799 :       if( fd_pack_unwritable_contains( acct ) ) continue; /* No need to track sysvars because they can't be writable */
    1060             : 
    1061     2559288 :       fd_pack_addr_use_t * use = acct_uses_query( acct_in_use,  *acct, NULL );
    1062     2559288 :       if( use ) conflicts |= (use->in_use_by & FD_PACK_IN_USE_WRITABLE) ? use->in_use_by : 0UL;
    1063     2559288 :     }
    1064             : 
    1065    13077363 :     if( FD_UNLIKELY( conflicts ) ) {
    1066           0 :       slow_path++;
    1067           0 :       continue;
    1068           0 :     }
    1069             : 
    1070             :     /* Include this transaction in the microblock! */
    1071    13077363 :     FD_PACK_BITSET_OR( bitset_rw_in_use, cur->rw_bitset );
    1072    13077363 :     FD_PACK_BITSET_OR( bitset_w_in_use,  cur->w_bitset  );
    1073             : 
    1074    13077363 :     if(
    1075     4359121 : #if FD_HAS_AVX512 && FD_PACK_USE_NON_TEMPORAL_MEMCPY
    1076     4359121 :         FD_LIKELY( cur->txn->payload_sz>=1024UL )
    1077             : #else
    1078     8718242 :         0
    1079     8718242 : #endif
    1080    13077363 :       ) {
    1081        4225 : #if FD_HAS_AVX512 && FD_PACK_USE_NON_TEMPORAL_MEMCPY
    1082        4225 :       _mm512_stream_si512( (void*)(out->payload+   0UL), _mm512_load_epi64( cur->txn->payload+   0UL ) );
    1083        4225 :       _mm512_stream_si512( (void*)(out->payload+  64UL), _mm512_load_epi64( cur->txn->payload+  64UL ) );
    1084        4225 :       _mm512_stream_si512( (void*)(out->payload+ 128UL), _mm512_load_epi64( cur->txn->payload+ 128UL ) );
    1085        4225 :       _mm512_stream_si512( (void*)(out->payload+ 192UL), _mm512_load_epi64( cur->txn->payload+ 192UL ) );
    1086        4225 :       _mm512_stream_si512( (void*)(out->payload+ 256UL), _mm512_load_epi64( cur->txn->payload+ 256UL ) );
    1087        4225 :       _mm512_stream_si512( (void*)(out->payload+ 320UL), _mm512_load_epi64( cur->txn->payload+ 320UL ) );
    1088        4225 :       _mm512_stream_si512( (void*)(out->payload+ 384UL), _mm512_load_epi64( cur->txn->payload+ 384UL ) );
    1089        4225 :       _mm512_stream_si512( (void*)(out->payload+ 448UL), _mm512_load_epi64( cur->txn->payload+ 448UL ) );
    1090        4225 :       _mm512_stream_si512( (void*)(out->payload+ 512UL), _mm512_load_epi64( cur->txn->payload+ 512UL ) );
    1091        4225 :       _mm512_stream_si512( (void*)(out->payload+ 576UL), _mm512_load_epi64( cur->txn->payload+ 576UL ) );
    1092        4225 :       _mm512_stream_si512( (void*)(out->payload+ 640UL), _mm512_load_epi64( cur->txn->payload+ 640UL ) );
    1093        4225 :       _mm512_stream_si512( (void*)(out->payload+ 704UL), _mm512_load_epi64( cur->txn->payload+ 704UL ) );
    1094        4225 :       _mm512_stream_si512( (void*)(out->payload+ 768UL), _mm512_load_epi64( cur->txn->payload+ 768UL ) );
    1095        4225 :       _mm512_stream_si512( (void*)(out->payload+ 832UL), _mm512_load_epi64( cur->txn->payload+ 832UL ) );
    1096        4225 :       _mm512_stream_si512( (void*)(out->payload+ 896UL), _mm512_load_epi64( cur->txn->payload+ 896UL ) );
    1097        4225 :       _mm512_stream_si512( (void*)(out->payload+ 960UL), _mm512_load_epi64( cur->txn->payload+ 960UL ) );
    1098        4225 :       _mm512_stream_si512( (void*)(out->payload+1024UL), _mm512_load_epi64( cur->txn->payload+1024UL ) );
    1099        4225 :       _mm512_stream_si512( (void*)(out->payload+1088UL), _mm512_load_epi64( cur->txn->payload+1088UL ) );
    1100        4225 :       _mm512_stream_si512( (void*)(out->payload+1152UL), _mm512_load_epi64( cur->txn->payload+1152UL ) );
    1101        4225 :       _mm512_stream_si512( (void*)(out->payload+1216UL), _mm512_load_epi64( cur->txn->payload+1216UL ) );
    1102             :       /* Copied out to 1280 bytes, which copies some other fields we needed to
    1103             :          copy anyway. */
    1104        4225 :       FD_STATIC_ASSERT( offsetof(fd_txn_p_t, payload_sz     )+sizeof(((fd_txn_p_t*)NULL)->payload_sz    )<=1280UL, nt_memcpy );
    1105        4225 :       FD_STATIC_ASSERT( offsetof(fd_txn_p_t, blockhash_slot )+sizeof(((fd_txn_p_t*)NULL)->blockhash_slot)<=1280UL, nt_memcpy );
    1106        4225 :       FD_STATIC_ASSERT( offsetof(fd_txn_p_t, flags          )+sizeof(((fd_txn_p_t*)NULL)->flags         )<=1280UL, nt_memcpy );
    1107        4225 :       FD_STATIC_ASSERT( offsetof(fd_txn_p_t, _              )                                            <=1280UL, nt_memcpy );
    1108        4225 :       const ulong offset_into_txn = 1280UL - offsetof(fd_txn_p_t, _ );
    1109        4225 :       fd_memcpy( offset_into_txn+(uchar *)TXN(out), offset_into_txn+(uchar const *)txn,
    1110        4225 :           fd_ulong_max( offset_into_txn, fd_txn_footprint( txn->instr_cnt, txn->addr_table_lookup_cnt ) )-offset_into_txn );
    1111        4225 : #endif
    1112    13073138 :     } else {
    1113    13073138 :       fd_memcpy( out->payload, cur->txn->payload, cur->txn->payload_sz                                           );
    1114    13073138 :       fd_memcpy( TXN(out),     txn,               fd_txn_footprint( txn->instr_cnt, txn->addr_table_lookup_cnt ) );
    1115    13073138 :       out->payload_sz                      = cur->txn->payload_sz;
    1116    13073138 :       out->pack_cu.requested_execution_cus = cur->txn->pack_cu.requested_execution_cus;
    1117    13073138 :       out->pack_cu.non_execution_cus       = cur->txn->pack_cu.non_execution_cus;
    1118    13073138 :       out->flags                           = cur->txn->flags;
    1119    13073138 :     }
    1120    13077363 :     out++;
    1121             : 
    1122    13077363 :     for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
    1123    27316032 :         iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1124    14238669 :       fd_acct_addr_t acct_addr = *ACCT_ITER_TO_PTR( iter );
    1125             : 
    1126    14238669 :       fd_pack_addr_use_t * in_wcost_table = acct_uses_query( writer_costs, acct_addr, NULL );
    1127    14238669 :       if( !in_wcost_table ) {
    1128      787788 :         in_wcost_table = acct_uses_insert( writer_costs, acct_addr );
    1129      787788 :         in_wcost_table->total_cost = 0UL;
    1130      787788 :         written_list[ written_list_cnt ] = in_wcost_table;
    1131      787788 :         written_list_cnt = fd_ulong_min( written_list_cnt+1UL, written_list_max-1UL );
    1132      787788 :       }
    1133    14238669 :       in_wcost_table->total_cost += cur->compute_est;
    1134             : 
    1135    14238669 :       fd_pack_addr_use_t * use = acct_uses_insert( acct_in_use, acct_addr );
    1136    14238669 :       use->in_use_by = bank_tile_mask | FD_PACK_IN_USE_WRITABLE;
    1137             : 
    1138    14238669 :       use_by_bank[use_by_bank_cnt++] = *use;
    1139             : 
    1140             :       /* If there aren't any more references to this account in the
    1141             :          heap, it can't cause any conflicts.  That means we actually
    1142             :          don't need to record that we are using it, which is good
    1143             :          because we want to release the bit. */
    1144    14238669 :       release_result_t ret = release_bit_reference( pack, &acct_addr );
    1145    14238669 :       FD_PACK_BITSET_CLEARN( bitset_rw_in_use, ret.clear_rw_bit );
    1146    14238669 :       FD_PACK_BITSET_CLEARN( bitset_w_in_use,  ret.clear_w_bit  );
    1147    14238669 :     }
    1148    13077363 :     for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY );
    1149    16623162 :         iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1150             : 
    1151     3545799 :       fd_acct_addr_t acct_addr = *ACCT_ITER_TO_PTR( iter );
    1152             : 
    1153     3545799 :       if( fd_pack_unwritable_contains( &acct_addr ) ) continue; /* No need to track sysvars because they can't be writable */
    1154             : 
    1155     2559288 :       fd_pack_addr_use_t * use = acct_uses_query( acct_in_use,  acct_addr, NULL );
    1156     2559288 :       if( !use ) { use = acct_uses_insert( acct_in_use, acct_addr ); use->in_use_by = 0UL; }
    1157             : 
    1158     2559288 :       if( !(use->in_use_by & bank_tile_mask) ) use_by_bank[use_by_bank_cnt++] = *use;
    1159     2559288 :       use->in_use_by |= bank_tile_mask;
    1160     2559288 :       use->in_use_by &= ~FD_PACK_IN_USE_BIT_CLEARED;
    1161             : 
    1162             : 
    1163     2559288 :       release_result_t ret = release_bit_reference( pack, &acct_addr );
    1164     2559288 :       FD_PACK_BITSET_CLEARN( bitset_rw_in_use, ret.clear_rw_bit );
    1165     2559288 :       FD_PACK_BITSET_CLEARN( bitset_w_in_use,  ret.clear_w_bit  );
    1166     2559288 :     }
    1167             : 
    1168    13077363 :     txns_scheduled  += 1UL;                      txn_limit       -= 1UL;
    1169    13077363 :     cus_scheduled   += cur->compute_est;         cu_limit        -= cur->compute_est;
    1170    13077363 :     bytes_scheduled += cur->txn->payload_sz;     byte_limit      -= cur->txn->payload_sz;
    1171             : 
    1172    13077363 :     fd_ed25519_sig_t const * sig0 = fd_txn_get_signatures( txn, cur->txn->payload );
    1173             : 
    1174    13077363 :     fd_pack_sig_to_txn_t * in_tbl = sig2txn_query( pack->signature_map, sig0, NULL );
    1175    13077363 :     sig2txn_remove( pack->signature_map, in_tbl );
    1176             : 
    1177    13077363 :     expq_remove( pack->expiration_q, cur->expq_idx );
    1178    13077363 :     treap_idx_remove( sched_from, _cur, pool );
    1179    13077363 :     trp_pool_idx_release( pool, _cur );
    1180    13077363 :     pack->pending_txn_cnt--;
    1181             : 
    1182    13077363 :     if( FD_UNLIKELY( (cu_limit<smallest_in_treap->cus) | (txn_limit==0UL) | (byte_limit<smallest_in_treap->bytes) ) ) break;
    1183    13077363 :   }
    1184             : 
    1185      759843 :   FD_MCNT_INC( PACK, TRANSACTION_SCHEDULE_TAKEN,      txns_scheduled );
    1186      759843 :   FD_MCNT_INC( PACK, TRANSACTION_SCHEDULE_CU_LIMIT,   cu_limit_c     );
    1187      759843 :   FD_MCNT_INC( PACK, TRANSACTION_SCHEDULE_FAST_PATH,  fast_path      );
    1188      759843 :   FD_MCNT_INC( PACK, TRANSACTION_SCHEDULE_BYTE_LIMIT, byte_limit_c   );
    1189      759843 :   FD_MCNT_INC( PACK, TRANSACTION_SCHEDULE_WRITE_COST, write_limit_c  );
    1190      759843 :   FD_MCNT_INC( PACK, TRANSACTION_SCHEDULE_SLOW_PATH,  slow_path      );
    1191             : 
    1192             : #if DETAILED_LOGGING
    1193             :   FD_LOG_NOTICE(( "cu_limit: %lu, fast_path: %lu, slow_path: %lu", cu_limit_c, fast_path, slow_path ));
    1194             : #endif
    1195             : 
    1196             :   /* If we scanned the whole treap and didn't break early, we now have a
    1197             :      better estimate of the smallest. */
    1198      759843 :   if( FD_UNLIKELY( treap_rev_iter_done( prev ) ) ) {
    1199      168714 :     smallest_in_treap->cus   = min_cus;
    1200      168714 :     smallest_in_treap->bytes = min_bytes;
    1201      168714 :   }
    1202             : 
    1203      759843 :   pack->use_by_bank_cnt[bank_tile] = use_by_bank_cnt;
    1204      759843 :   FD_PACK_BITSET_COPY( pack->bitset_rw_in_use, bitset_rw_in_use );
    1205      759843 :   FD_PACK_BITSET_COPY( pack->bitset_w_in_use,  bitset_w_in_use  );
    1206             : 
    1207      759843 :   pack->written_list_cnt = written_list_cnt;
    1208             : 
    1209      759843 :   sched_return_t to_return = { .cus_scheduled=cus_scheduled, .txns_scheduled=txns_scheduled, .bytes_scheduled=bytes_scheduled };
    1210      759843 :   return to_return;
    1211     2214648 : }
    1212             : 
    1213             : void
    1214             : fd_pack_microblock_complete( fd_pack_t * pack,
    1215      738216 :                              ulong       bank_tile ) {
    1216             :   /* If the account is in use writably, and it's in use by this banking
    1217             :      tile, then this banking tile must be the sole writer to it, so it's
    1218             :      always okay to clear the writable bit. */
    1219      738216 :   ulong clear_mask = ~((1UL<<bank_tile) | FD_PACK_IN_USE_WRITABLE);
    1220             : 
    1221      738216 :   FD_PACK_BITSET_DECLARE( bitset_rw_in_use );
    1222      738216 :   FD_PACK_BITSET_DECLARE( bitset_w_in_use  );
    1223      738216 :   FD_PACK_BITSET_COPY( bitset_rw_in_use, pack->bitset_rw_in_use );
    1224      738216 :   FD_PACK_BITSET_COPY( bitset_w_in_use,  pack->bitset_w_in_use  );
    1225             : 
    1226      738216 :   fd_pack_addr_use_t * base = pack->use_by_bank[bank_tile];
    1227    16920126 :   for( ulong i=0UL; i<pack->use_by_bank_cnt[bank_tile]; i++ ) {
    1228    16181910 :     fd_pack_addr_use_t * use = acct_uses_query( pack->acct_in_use, base[i].key, NULL );
    1229    16181910 :     FD_TEST( use );
    1230    16181910 :     use->in_use_by &= clear_mask;
    1231             : 
    1232             :     /* In order to properly bound the size of bitset_map, we need to
    1233             :        release the "reference" to the account when we schedule it.
    1234             :        However, that poses a bit of a problem here, because by the time
    1235             :        we complete the microblock, that account could have been assigned
    1236             :        a different bit in the bitset.  The scheduling step tells us if
    1237             :        that is the case, and if so, we know that the bits in
    1238             :        bitset_w_in_use and bitset_rw_in_use were already cleared as
    1239             :        necessary.
    1240             : 
    1241             :        Note that it's possible for BIT_CLEARED to be set and then unset
    1242             :        by later uses, but then the account would be in use on other
    1243             :        banks, so we wouldn't try to observe the old value.  For example:
    1244             :        Suppose bit 0->account A, bit 1->account B, and we have two
    1245             :        transactions that read A, B.  We schedule a microblock to bank 0,
    1246             :        taking both transactions, which sets the counts for A, B to 0,
    1247             :        and releases the bits, clearing bits 0 and 1, and setting
    1248             :        BIT_CLEARED.  Then we get two more transactions that read
    1249             :        accounts C, D, A, B, and they get assigned 0->C, 1->D, 2->A,
    1250             :        3->B.  We try to schedule a microblock to bank 1 that takes one
    1251             :        of those transactions.   This unsets BIT_CLEARED for A, B.
    1252             :        Finally, the first microblock completes.  Even though the bitset
    1253             :        map has the new bits for A and B which are "wrong" compared to
    1254             :        when the transaction was initially scheduled, those bits have
    1255             :        already been cleared and reset properly in the bitset as needed.
    1256             :        A and B will still be in use by bank 1, so we won't clear any
    1257             :        bits.  If, on the other hand, the microblock scheduled to bank 1
    1258             :        completes first, bits 0 and 1 will be cleared for accounts C and
    1259             :        D, while bits 2 and 3 will remain set, which is correct.  Then
    1260             :        when bank 0 completes, bits 2 and 3 will be cleared. */
    1261    16181910 :     if( FD_LIKELY( !use->in_use_by ) ) { /* if in_use_by==0, doesn't include BIT_CLEARED */
    1262     3403176 :       fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, base[i].key, NULL );
    1263     3403176 :       FD_TEST( q );
    1264     3403176 :       FD_PACK_BITSET_CLEARN( bitset_w_in_use,  q->bit );
    1265     3403176 :       FD_PACK_BITSET_CLEARN( bitset_rw_in_use, q->bit );
    1266     3403176 :     }
    1267    16181910 :     if( FD_LIKELY( !(use->in_use_by & ~FD_PACK_IN_USE_BIT_CLEARED) ) ) acct_uses_remove( pack->acct_in_use, use );
    1268    16181910 :   }
    1269             : 
    1270      738216 :   pack->use_by_bank_cnt[bank_tile] = 0UL;
    1271             : 
    1272      738216 :   FD_PACK_BITSET_COPY( pack->bitset_rw_in_use, bitset_rw_in_use );
    1273      738216 :   FD_PACK_BITSET_COPY( pack->bitset_w_in_use,  bitset_w_in_use  );
    1274             : 
    1275             :   /* outstanding_microblock_mask never has the writable bit set, so we
    1276             :      don't care about clearing it here either. */
    1277      738216 :   pack->outstanding_microblock_mask &= clear_mask;
    1278      738216 : }
    1279             : 
    1280             : 
    1281             : ulong
    1282             : fd_pack_schedule_next_microblock( fd_pack_t *  pack,
    1283             :                                   ulong        total_cus,
    1284             :                                   float        vote_fraction,
    1285             :                                   ulong        bank_tile,
    1286      738216 :                                   fd_txn_p_t * out ) {
    1287             : 
    1288             :   /* TODO: Decide if these are exactly how we want to handle limits */
    1289      738216 :   total_cus = fd_ulong_min( total_cus, pack->lim->max_cost_per_block - pack->cumulative_block_cost );
    1290      738216 :   ulong vote_cus = fd_ulong_min( (ulong)((float)total_cus * vote_fraction),
    1291      738216 :                                  pack->lim->max_vote_cost_per_block - pack->cumulative_vote_cost );
    1292      738216 :   ulong vote_reserved_txns = fd_ulong_min( vote_cus/FD_PACK_TYPICAL_VOTE_COST,
    1293      738216 :                                            (ulong)((float)pack->lim->max_txn_per_microblock * vote_fraction) );
    1294             : 
    1295             : 
    1296      738216 :   if( FD_UNLIKELY( (pack->microblock_cnt>=pack->lim->max_microblocks_per_block) ) ) {
    1297           0 :     FD_MCNT_INC( PACK, MICROBLOCK_PER_BLOCK_LIMIT, 1UL );
    1298           0 :     return 0UL;
    1299           0 :   }
    1300      738216 :   if( FD_UNLIKELY( pack->data_bytes_consumed+MICROBLOCK_DATA_OVERHEAD+FD_TXN_MIN_SERIALIZED_SZ>pack->lim->max_data_bytes_per_block) ) {
    1301           0 :     FD_MCNT_INC( PACK, DATA_PER_BLOCK_LIMIT, 1UL );
    1302           0 :     return 0UL;
    1303           0 :   }
    1304             : 
    1305      738216 :   ulong cu_limit  = total_cus - vote_cus;
    1306      738216 :   ulong txn_limit = pack->lim->max_txn_per_microblock - vote_reserved_txns;
    1307      738216 :   ulong scheduled = 0UL;
    1308      738216 :   ulong byte_limit = pack->lim->max_data_bytes_per_block - pack->data_bytes_consumed - MICROBLOCK_DATA_OVERHEAD;
    1309             : 
    1310      738216 :   sched_return_t status, status1;
    1311             : 
    1312             :   /* Try to schedule non-vote transactions */
    1313      738216 :   status = fd_pack_schedule_impl( pack, pack->pending,       cu_limit, txn_limit,          byte_limit, bank_tile, pack->pending_smallest,       out+scheduled );
    1314             : 
    1315      738216 :   scheduled                   += status.txns_scheduled;            txn_limit  -= status.txns_scheduled;
    1316      738216 :   pack->cumulative_block_cost += status.cus_scheduled;             cu_limit   -= status.cus_scheduled;
    1317      738216 :   pack->data_bytes_consumed   += status.bytes_scheduled;           byte_limit -= status.bytes_scheduled;
    1318             : 
    1319             : 
    1320             :   /* Schedule vote transactions */
    1321      738216 :   status1= fd_pack_schedule_impl( pack, pack->pending_votes, vote_cus, vote_reserved_txns, byte_limit, bank_tile, pack->pending_votes_smallest, out+scheduled );
    1322             : 
    1323      738216 :   scheduled                   += status1.txns_scheduled;
    1324      738216 :   pack->cumulative_vote_cost  += status1.cus_scheduled;
    1325      738216 :   pack->cumulative_block_cost += status1.cus_scheduled;
    1326      738216 :   pack->data_bytes_consumed   += status1.bytes_scheduled;
    1327      738216 :   byte_limit                  -= status1.bytes_scheduled;
    1328             :   /* Add any remaining CUs/txns to the non-vote limits */
    1329      738216 :   txn_limit += vote_reserved_txns - status1.txns_scheduled;
    1330      738216 :   cu_limit  += vote_cus - status1.cus_scheduled;
    1331             : 
    1332             : 
    1333             :   /* Fill any remaining space with non-vote transactions */
    1334      738216 :   status = fd_pack_schedule_impl( pack, pack->pending,       cu_limit, txn_limit,          byte_limit, bank_tile, pack->pending_smallest,       out+scheduled );
    1335             : 
    1336      738216 :   scheduled                   += status.txns_scheduled;
    1337      738216 :   pack->cumulative_block_cost += status.cus_scheduled;
    1338      738216 :   pack->data_bytes_consumed   += status.bytes_scheduled;
    1339             : 
    1340      738216 :   ulong nonempty = (ulong)(scheduled>0UL);
    1341      738216 :   pack->microblock_cnt              += nonempty;
    1342      738216 :   pack->outstanding_microblock_mask |= nonempty << bank_tile;
    1343      738216 :   pack->data_bytes_consumed         += nonempty * MICROBLOCK_DATA_OVERHEAD;
    1344             : 
    1345             :   /* Update metrics counters */
    1346      738216 :   FD_MGAUGE_SET( PACK, AVAILABLE_TRANSACTIONS,      pack->pending_txn_cnt                );
    1347      738216 :   FD_MGAUGE_SET( PACK, AVAILABLE_VOTE_TRANSACTIONS, treap_ele_cnt( pack->pending_votes ) );
    1348      738216 :   FD_MGAUGE_SET( PACK, CUS_CONSUMED_IN_BLOCK,       pack->cumulative_block_cost          );
    1349             : 
    1350      738216 :   fd_histf_sample( pack->txn_per_microblock,  scheduled              );
    1351      738216 :   fd_histf_sample( pack->vote_per_microblock, status1.txns_scheduled );
    1352             : 
    1353      246072 : #if FD_HAS_AVX512 && FD_PACK_USE_NON_TEMPORAL_MEMCPY
    1354      246072 :   _mm_sfence();
    1355      246072 : #endif
    1356             : 
    1357      738216 :   return scheduled;
    1358      738216 : }
    1359             : 
    1360      268194 : ulong fd_pack_bank_tile_cnt( fd_pack_t const * pack ) { return pack->bank_tile_cnt;   }
    1361             : 
    1362             : 
    1363             : void
    1364             : fd_pack_set_block_limits( fd_pack_t * pack,
    1365             :                           ulong       max_microblocks_per_block,
    1366           0 :                           ulong       max_data_bytes_per_block ) {
    1367           0 :   pack->lim->max_microblocks_per_block = max_microblocks_per_block;
    1368           0 :   pack->lim->max_data_bytes_per_block  = max_data_bytes_per_block;
    1369           0 : }
    1370             : 
    1371             : void
    1372             : fd_pack_rebate_cus( fd_pack_t        * pack,
    1373             :                     fd_txn_p_t const * txns,
    1374           6 :                     ulong              txn_cnt ) {
    1375           6 :   fd_pack_addr_use_t * writer_costs = pack->writer_costs;
    1376             : 
    1377           6 :   ulong cumulative_vote_cost   = pack->cumulative_vote_cost;
    1378           6 :   ulong cumulative_block_cost  = pack->cumulative_block_cost;
    1379           6 :   ulong data_bytes_consumed    = pack->data_bytes_consumed;
    1380           6 :   ulong cumulative_rebated_cus = pack->cumulative_rebated_cus;
    1381             : 
    1382          18 :   for( ulong i=0UL; i<txn_cnt; i++ ) {
    1383          12 :     fd_txn_p_t const * txn = txns+i;
    1384          12 :     ulong rebated_cus   = txn->bank_cu.rebated_cus;
    1385          12 :     int   in_block      = !!(txn->flags & FD_TXN_P_FLAGS_EXECUTE_SUCCESS);
    1386             : 
    1387          12 :     cumulative_block_cost  -= rebated_cus;
    1388          12 :     cumulative_vote_cost   -= fd_ulong_if( txn->flags & FD_TXN_P_FLAGS_IS_SIMPLE_VOTE, rebated_cus,     0UL );
    1389          12 :     data_bytes_consumed    -= fd_ulong_if( !in_block,                                  txn->payload_sz, 0UL );
    1390          12 :     cumulative_rebated_cus += rebated_cus;
    1391             : 
    1392          12 :     fd_acct_addr_t const * accts = fd_txn_get_acct_addrs( TXN(txn), txn->payload );
    1393             :     /* TODO: For now, we don't have a way to rebate writer costs for ALT
    1394             :        accounts.  We've thrown away the ALT expansion at this point.
    1395             :        The rebate system is going to be rewritten soon for performance,
    1396             :        so it's okay. */
    1397          12 :     for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( TXN(txn), FD_TXN_ACCT_CAT_WRITABLE & FD_TXN_ACCT_CAT_IMM );
    1398          36 :         iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1399             : 
    1400          24 :       ulong i=fd_txn_acct_iter_idx( iter );
    1401             : 
    1402          24 :       fd_pack_addr_use_t * in_wcost_table = acct_uses_query( writer_costs, accts[i], NULL );
    1403          24 :       if( FD_UNLIKELY( !in_wcost_table ) ) FD_LOG_ERR(( "Rebate to unknown written account" ));
    1404          24 :       in_wcost_table->total_cost -= rebated_cus;
    1405             :       /* Important: Even if this is 0, don't delete it from the table so
    1406             :          that the insert order doesn't get messed up. */
    1407          24 :     }
    1408          12 :   }
    1409             : 
    1410           6 :   pack->cumulative_vote_cost   = cumulative_vote_cost;
    1411           6 :   pack->cumulative_block_cost  = cumulative_block_cost;
    1412           6 :   pack->data_bytes_consumed    = data_bytes_consumed;
    1413           6 :   pack->cumulative_rebated_cus = cumulative_rebated_cus;
    1414           6 : }
    1415             : 
    1416             : 
    1417             : ulong
    1418             : fd_pack_expire_before( fd_pack_t * pack,
    1419           9 :                        ulong       expire_before ) {
    1420           9 :   expire_before = fd_ulong_max( expire_before, pack->expire_before );
    1421           9 :   ulong deleted_cnt = 0UL;
    1422           9 :   fd_pack_expq_t * prq = pack->expiration_q;
    1423          18 :   while( (expq_cnt( prq )>0UL) & (prq->expires_at<expire_before) ) {
    1424           9 :     fd_pack_ord_txn_t * expired = prq->txn;
    1425             : 
    1426           9 :     fd_ed25519_sig_t const * expired_sig = fd_txn_get_signatures( TXN( expired->txn ), expired->txn->payload );
    1427             :     /* fd_pack_delete_transaction also removes it from the heap */
    1428           9 :     fd_pack_delete_transaction( pack, expired_sig );
    1429           9 :     deleted_cnt++;
    1430           9 :   }
    1431             : 
    1432           9 :   pack->expire_before = expire_before;
    1433           9 :   return deleted_cnt;
    1434           9 : }
    1435             : 
    1436             : void
    1437        2646 : fd_pack_end_block( fd_pack_t * pack ) {
    1438        2646 :   fd_histf_sample( pack->net_cus_per_block,       pack->cumulative_block_cost                                );
    1439        2646 :   fd_histf_sample( pack->rebated_cus_per_block,   pack->cumulative_rebated_cus                               );
    1440        2646 :   fd_histf_sample( pack->scheduled_cus_per_block, pack->cumulative_rebated_cus + pack->cumulative_block_cost );
    1441             : 
    1442        2646 :   pack->microblock_cnt         = 0UL;
    1443        2646 :   pack->data_bytes_consumed    = 0UL;
    1444        2646 :   pack->cumulative_block_cost  = 0UL;
    1445        2646 :   pack->cumulative_vote_cost   = 0UL;
    1446        2646 :   pack->cumulative_rebated_cus = 0UL;
    1447             : 
    1448        2646 :   acct_uses_clear( pack->acct_in_use  );
    1449             : 
    1450        2646 :   if( FD_LIKELY( pack->written_list_cnt<pack->written_list_max-1UL ) ) {
    1451             :     /* The less dangerous way of doing this is to instead record the
    1452             :        keys we inserted and do a query followed by a delete for each
    1453             :        key.  The downside of that is that keys are 32 bytes and a
    1454             :        pointer is only 8 bytes, plus the computational cost for the
    1455             :        query.
    1456             : 
    1457             :        However, if we're careful, we can pull this off.  We require two
    1458             :        things.  First, we started from an empty map and did nothing but
    1459             :        insert and update.  In particular, no deletions.  Second, we have
    1460             :        to be careful to delete in the opposite order that we inserted.
    1461             :        This is essentially like unwinding the inserts we did.  The
    1462             :        common case is that the element after the one we delete will be
    1463             :        empty, so we'll hit that case.  It's possible that there's
    1464             :        another independent probe sequence that will be entirely intact
    1465             :        starting in the element after, but we'll never hit the MAP_MOVE
    1466             :        case. */
    1467      776193 :     for( ulong i=0UL; i<pack->written_list_cnt; i++ ) {
    1468      773547 :       acct_uses_remove( pack->writer_costs, pack->written_list[ pack->written_list_cnt - 1UL - i ] );
    1469      773547 :     }
    1470        2646 :   } else {
    1471           0 :     acct_uses_clear( pack->writer_costs );
    1472           0 :   }
    1473        2646 :   pack->written_list_cnt = 0UL;
    1474             : 
    1475        2646 :   FD_PACK_BITSET_CLEAR( pack->bitset_rw_in_use );
    1476        2646 :   FD_PACK_BITSET_CLEAR( pack->bitset_w_in_use  );
    1477             : 
    1478        9234 :   for( ulong i=0UL; i<pack->bank_tile_cnt; i++ ) pack->use_by_bank_cnt[i] = 0UL;
    1479             : 
    1480             :   /* If our stake is low and we don't become leader often, end_block
    1481             :      might get called on the order of O(1/hr), which feels too
    1482             :      infrequent to do anything related to metrics.  However, we only
    1483             :      update the histograms when we are leader, so this is actually a
    1484             :      good place to copy them. */
    1485        2646 :   FD_MHIST_COPY( PACK, TOTAL_TRANSACTIONS_PER_MICROBLOCK_COUNT, pack->txn_per_microblock  );
    1486        2646 :   FD_MHIST_COPY( PACK, VOTES_PER_MICROBLOCK_COUNT,              pack->vote_per_microblock );
    1487             : 
    1488        2646 :   FD_MGAUGE_SET( PACK, CUS_CONSUMED_IN_BLOCK, 0UL                           );
    1489        2646 :   FD_MHIST_COPY( PACK, CUS_SCHEDULED,         pack->scheduled_cus_per_block );
    1490        2646 :   FD_MHIST_COPY( PACK, CUS_REBATED,           pack->rebated_cus_per_block   );
    1491        2646 :   FD_MHIST_COPY( PACK, CUS_NET,               pack->net_cus_per_block       );
    1492        2646 : }
    1493             : 
    1494             : static void
    1495             : release_tree( treap_t           * treap,
    1496           0 :               fd_pack_ord_txn_t * pool ) {
    1497           0 :   treap_fwd_iter_t next;
    1498           0 :   for( treap_fwd_iter_t it=treap_fwd_iter_init( treap, pool ); !treap_fwd_iter_idx( it ); it=next ) {
    1499           0 :     next = treap_fwd_iter_next( it, pool );
    1500           0 :     ulong idx = treap_fwd_iter_idx( it );
    1501           0 :     treap_idx_remove    ( treap, idx, pool );
    1502           0 :     trp_pool_idx_release( pool,  idx       );
    1503           0 :   }
    1504           0 : }
    1505             : 
    1506             : void
    1507           0 : fd_pack_clear_all( fd_pack_t * pack ) {
    1508           0 :   pack->pending_txn_cnt        = 0UL;
    1509           0 :   pack->microblock_cnt         = 0UL;
    1510           0 :   pack->cumulative_block_cost  = 0UL;
    1511           0 :   pack->cumulative_vote_cost   = 0UL;
    1512           0 :   pack->cumulative_rebated_cus = 0UL;
    1513             : 
    1514           0 :   pack->pending_smallest->cus         = ULONG_MAX;
    1515           0 :   pack->pending_smallest->bytes       = ULONG_MAX;
    1516           0 :   pack->pending_votes_smallest->cus   = ULONG_MAX;
    1517           0 :   pack->pending_votes_smallest->bytes = ULONG_MAX;
    1518             : 
    1519           0 :   release_tree( pack->pending,         pack->pool );
    1520           0 :   release_tree( pack->pending_votes,   pack->pool );
    1521             : 
    1522           0 :   expq_remove_all( pack->expiration_q );
    1523             : 
    1524           0 :   acct_uses_clear( pack->acct_in_use  );
    1525           0 :   acct_uses_clear( pack->writer_costs );
    1526             : 
    1527           0 :   sig2txn_clear( pack->signature_map );
    1528             : 
    1529           0 :   FD_PACK_BITSET_CLEAR( pack->bitset_rw_in_use );
    1530           0 :   FD_PACK_BITSET_CLEAR( pack->bitset_w_in_use  );
    1531           0 :   bitset_map_clear( pack->acct_to_bitset );
    1532           0 :   pack->bitset_avail[ 0 ] = FD_PACK_BITSET_SLOWPATH;
    1533           0 :   for( ulong i=0UL; i<FD_PACK_BITSET_MAX; i++ ) pack->bitset_avail[ i+1UL ] = (ushort)i;
    1534           0 :   pack->bitset_avail_cnt = FD_PACK_BITSET_MAX;
    1535             : 
    1536           0 :   for( ulong i=0UL; i<pack->bank_tile_cnt; i++ ) pack->use_by_bank_cnt[i] = 0UL;
    1537           0 : }
    1538             : 
    1539             : int
    1540             : fd_pack_delete_transaction( fd_pack_t              * pack,
    1541        3189 :                             fd_ed25519_sig_t const * sig0 ) {
    1542        3189 :   fd_pack_sig_to_txn_t * in_tbl = sig2txn_query( pack->signature_map, sig0, NULL );
    1543             : 
    1544        3189 :   if( !in_tbl )
    1545          36 :     return 0;
    1546             : 
    1547             :   /* The static asserts enforce that the payload of the transaction is
    1548             :      the first element of the fd_pack_ord_txn_t struct.  The signature
    1549             :      we insert is 1 byte into the start of the payload. */
    1550        3153 :   fd_pack_ord_txn_t * containing = (fd_pack_ord_txn_t *)( (uchar*)in_tbl->key - 1UL );
    1551        3153 :   treap_t * root = NULL;
    1552        3153 :   int root_idx = containing->root;
    1553        3153 :   switch( root_idx ) {
    1554           0 :     case FD_ORD_TXN_ROOT_FREE:             /* Should be impossible */                                                return 0;
    1555        3114 :     case FD_ORD_TXN_ROOT_PENDING:          root = pack->pending;                                                     break;
    1556          39 :     case FD_ORD_TXN_ROOT_PENDING_VOTE:     root = pack->pending_votes;                                               break;
    1557        3153 :   }
    1558             : 
    1559        3153 :   fd_txn_t * txn = TXN( containing->txn );
    1560        3153 :   fd_acct_addr_t const * accts   = fd_txn_get_acct_addrs( txn, containing->txn->payload );
    1561        3153 :   fd_acct_addr_t const * alt_adj = containing->txn_e->alt_accts - fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM );
    1562        3153 :   for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
    1563       15603 :       iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1564             : 
    1565       12450 :     release_result_t ret = release_bit_reference( pack, ACCT_ITER_TO_PTR( iter ) );
    1566       12450 :     FD_PACK_BITSET_CLEARN( pack->bitset_rw_in_use, ret.clear_rw_bit );
    1567       12450 :     FD_PACK_BITSET_CLEARN( pack->bitset_w_in_use,  ret.clear_w_bit  );
    1568       12450 :   }
    1569             : 
    1570        3153 :   for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY );
    1571       18756 :       iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1572       15603 :     if( FD_UNLIKELY( fd_pack_unwritable_contains( ACCT_ITER_TO_PTR( iter ) ) ) ) continue;
    1573             : 
    1574       12372 :     release_result_t ret = release_bit_reference( pack, ACCT_ITER_TO_PTR( iter ) );
    1575       12372 :     FD_PACK_BITSET_CLEARN( pack->bitset_rw_in_use, ret.clear_rw_bit );
    1576       12372 :     FD_PACK_BITSET_CLEARN( pack->bitset_w_in_use,  ret.clear_w_bit  );
    1577       12372 :   }
    1578        3153 :   expq_remove( pack->expiration_q, containing->expq_idx );
    1579        3153 :   treap_ele_remove( root, containing, pack->pool );
    1580        3153 :   trp_pool_ele_release( pack->pool, containing );
    1581        3153 :   sig2txn_remove( pack->signature_map, in_tbl );
    1582        3153 :   pack->pending_txn_cnt--;
    1583             : 
    1584        3153 :   return 1;
    1585        3153 : }
    1586             : 
    1587             : 
    1588             : int
    1589             : fd_pack_verify( fd_pack_t * pack,
    1590           0 :                 void      * scratch ) {
    1591             :   /* Invariants:
    1592             :      sig2txn_query has exact same contents as all treaps combined
    1593             :      root matches treap
    1594             :      Keys of acct_to_bitset is exactly union of all accounts in all
    1595             :             transactions in treaps, with ref counted appropriately
    1596             :      bits in bitset_avail is complement of bits allocated in
    1597             :             acct_to_bitset
    1598             :      expires_at consistent between treap, prq */
    1599             : 
    1600             :   /* TODO:
    1601             :      bitset_{r}w_in_use = bitset_map_query( everything in acct_in_use that doesn't have FD_PACK_IN_USE_BIT_CLEARED )
    1602             :      use_by_bank does not contain duplicates
    1603             :      use_by_bank consistent with acct_in_use
    1604             :      bitset_w_in_use & bitset_rw_in_use == bitset_w_in_use */
    1605           0 : #define VERIFY_TEST( cond, ... ) do {   \
    1606           0 :     if( FD_UNLIKELY( !(cond) ) ) {      \
    1607           0 :       FD_LOG_WARNING(( __VA_ARGS__ ));  \
    1608           0 :       return -(__LINE__);               \
    1609           0 :     }                                   \
    1610           0 :   } while( 0 )
    1611             : 
    1612           0 :   ulong max_acct_in_treap  = pack->pack_depth * FD_TXN_ACCT_ADDR_MAX;
    1613           0 :   int lg_acct_in_trp = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_treap  ) );
    1614           0 :   void * _bitset_map_copy = scratch;
    1615           0 :   void * _bitset_map_orig = bitset_map_leave( pack->acct_to_bitset );
    1616           0 :   fd_memcpy( _bitset_map_copy, _bitset_map_orig, bitset_map_footprint( lg_acct_in_trp ) );
    1617             : 
    1618           0 :   fd_pack_bitset_acct_mapping_t * bitset_copy = bitset_map_join( _bitset_map_copy );
    1619             : 
    1620             :   /* Check that each bit is in exactly one place */
    1621           0 :   FD_PACK_BITSET_DECLARE( processed ); FD_PACK_BITSET_CLEAR( processed );
    1622           0 :   FD_PACK_BITSET_DECLARE( bit       ); FD_PACK_BITSET_CLEAR( bit       );
    1623           0 :   FD_PACK_BITSET_DECLARE( full      ); FD_PACK_BITSET_CLEAR( full      );
    1624             : 
    1625           0 :   if( FD_UNLIKELY( pack->bitset_avail[0]!=FD_PACK_BITSET_SLOWPATH ) ) return -1;
    1626           0 :   for( ulong i=1UL; i<=pack->bitset_avail_cnt; i++ ) {
    1627           0 :     FD_PACK_BITSET_CLEAR( bit );
    1628           0 :     FD_PACK_BITSET_SETN( bit, pack->bitset_avail[ i ] );
    1629           0 :     VERIFY_TEST( FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, processed, processed ),
    1630           0 :         "bit %hu in avail set twice", pack->bitset_avail[ i ] );
    1631           0 :     FD_PACK_BITSET_OR( processed, bit );
    1632           0 :   }
    1633             : 
    1634           0 :   ulong total_references = 0UL;
    1635           0 :   for( ulong i=0UL; i<bitset_map_slot_cnt( bitset_copy ); i++ ) {
    1636           0 :     if( !bitset_map_key_inval( bitset_copy[ i ].key ) ) {
    1637           0 :       VERIFY_TEST( bitset_copy[ i ].ref_cnt>0UL, "account address in table with 0 ref count" );
    1638             : 
    1639           0 :       total_references += bitset_copy[ i ].ref_cnt;
    1640             : 
    1641           0 :       FD_PACK_BITSET_CLEAR( bit );
    1642           0 :       FD_PACK_BITSET_SETN( bit, bitset_copy[ i ].bit );
    1643           0 :       VERIFY_TEST( FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, processed, processed ), "bit %hu used twice", bitset_copy[ i ].bit );
    1644           0 :       FD_PACK_BITSET_OR( processed, bit );
    1645           0 :     }
    1646           0 :   }
    1647           0 :   for( ulong i=0UL; i<FD_PACK_BITSET_MAX; i++ ) {
    1648           0 :     FD_PACK_BITSET_CLEAR( bit );
    1649           0 :     FD_PACK_BITSET_SETN( bit, i );
    1650           0 :     VERIFY_TEST( !FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, processed, processed ), "bit %lu missing", i );
    1651           0 :     FD_PACK_BITSET_SETN( full, i );
    1652           0 :   }
    1653             : 
    1654             : 
    1655           0 :   fd_pack_ord_txn_t  * pool = pack->pool;
    1656           0 :   treap_t * treaps[ 2 ] = { pack->pending, pack->pending_votes };
    1657           0 :   ulong txn_cnt = 0UL;
    1658             : 
    1659           0 :   for( ulong k=0UL; k<2; k++ ) {
    1660           0 :     treap_t * treap = treaps[ k ];
    1661             : 
    1662           0 :     for( treap_rev_iter_t _cur=treap_rev_iter_init( treap, pool ); !treap_rev_iter_done( _cur );
    1663           0 :         _cur=treap_rev_iter_next( _cur, pool ) ) {
    1664           0 :       txn_cnt++;
    1665           0 :       fd_pack_ord_txn_t const * cur = treap_rev_iter_ele_const( _cur, pool );
    1666           0 :       fd_txn_t const * txn = TXN(cur->txn);
    1667           0 :       fd_acct_addr_t const * accts   = fd_txn_get_acct_addrs( txn, cur->txn->payload );
    1668           0 :       fd_acct_addr_t const * alt_adj = cur->txn_e->alt_accts - fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM );
    1669             : 
    1670           0 :       fd_ed25519_sig_t const * sig0 = fd_txn_get_signatures( txn, cur->txn->payload );
    1671             : 
    1672           0 :       fd_pack_sig_to_txn_t * in_tbl = sig2txn_query( pack->signature_map, sig0, NULL );
    1673           0 :       VERIFY_TEST( in_tbl, "signature missing from sig2txn" );
    1674           0 :       VERIFY_TEST( in_tbl->key==sig0, "signature in sig2txn inconsistent" );
    1675           0 :       VERIFY_TEST( (ulong)(cur->root)==k+1, "treap element had bad root" );
    1676           0 :       VERIFY_TEST( cur->expires_at>=pack->expire_before, "treap element expired" );
    1677             : 
    1678           0 :       fd_pack_expq_t const * eq = pack->expiration_q + cur->expq_idx;
    1679           0 :       VERIFY_TEST( eq->txn==cur, "expq inconsistent" );
    1680           0 :       VERIFY_TEST( eq->expires_at==cur->expires_at, "expq expires_at inconsistent" );
    1681             : 
    1682           0 :       FD_PACK_BITSET_DECLARE( complement );
    1683           0 :       FD_PACK_BITSET_COPY( complement, full );
    1684           0 :       for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
    1685           0 :           iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1686           0 :         fd_acct_addr_t acct = *ACCT_ITER_TO_PTR( iter );
    1687             : 
    1688           0 :         fd_pack_bitset_acct_mapping_t * q = bitset_map_query( bitset_copy, acct, NULL );
    1689           0 :         VERIFY_TEST( q, "account in transaction missing from bitset mapping" );
    1690           0 :         VERIFY_TEST( q->ref_cnt>0UL, "account in transaction ref_cnt already 0" );
    1691           0 :         q->ref_cnt--;
    1692           0 :         total_references--;
    1693             : 
    1694           0 :         FD_PACK_BITSET_CLEAR( bit );
    1695           0 :         FD_PACK_BITSET_SETN( bit, q->bit );
    1696           0 :         if( q->bit<FD_PACK_BITSET_MAX ) {
    1697           0 :           VERIFY_TEST( !FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, cur->rw_bitset, cur->rw_bitset ), "missing from rw bitset" );
    1698           0 :           VERIFY_TEST( !FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, cur->w_bitset,  cur->w_bitset ), "missing from w bitset" );
    1699           0 :         }
    1700           0 :         FD_PACK_BITSET_CLEARN( complement, q->bit );
    1701           0 :       }
    1702           0 :       VERIFY_TEST( FD_PACK_BITSET_INTERSECT4_EMPTY( complement, complement, cur->w_bitset,  cur->w_bitset ), "extra in w bitset" );
    1703             : 
    1704           0 :       for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY );
    1705           0 :           iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1706             : 
    1707           0 :         fd_acct_addr_t acct = *ACCT_ITER_TO_PTR( iter );
    1708           0 :         if( FD_UNLIKELY( fd_pack_unwritable_contains( &acct ) ) ) continue;
    1709           0 :         fd_pack_bitset_acct_mapping_t * q = bitset_map_query( bitset_copy, acct, NULL );
    1710           0 :         VERIFY_TEST( q, "account in transaction missing from bitset mapping" );
    1711           0 :         VERIFY_TEST( q->ref_cnt>0UL, "account in transaction ref_cnt already 0" );
    1712           0 :         q->ref_cnt--;
    1713           0 :         total_references--;
    1714             : 
    1715           0 :         FD_PACK_BITSET_CLEAR( bit );
    1716           0 :         FD_PACK_BITSET_SETN( bit, q->bit );
    1717           0 :         if( q->bit<FD_PACK_BITSET_MAX ) {
    1718           0 :           VERIFY_TEST( !FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, cur->rw_bitset, cur->rw_bitset ), "missing from rw bitset" );
    1719           0 :         }
    1720           0 :         FD_PACK_BITSET_CLEARN( complement, q->bit );
    1721           0 :       }
    1722           0 :       VERIFY_TEST( FD_PACK_BITSET_INTERSECT4_EMPTY( complement, complement, cur->rw_bitset,  cur->rw_bitset ), "extra in rw bitset" );
    1723           0 :     }
    1724           0 :   }
    1725             : 
    1726           0 :   bitset_map_leave( bitset_copy );
    1727             : 
    1728           0 :   VERIFY_TEST( total_references==0UL, "extra references in bitset mapping" );
    1729           0 :   VERIFY_TEST( txn_cnt==sig2txn_key_cnt( pack->signature_map ), "extra signatures in sig2txn" );
    1730             : 
    1731           0 :   bitset_map_join( _bitset_map_orig );
    1732             : 
    1733           0 :   ulong max_acct_in_flight = pack->bank_tile_cnt * (FD_TXN_ACCT_ADDR_MAX * pack->lim->max_txn_per_microblock + 1UL);
    1734           0 :   int lg_uses_tbl_sz = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_flight ) );
    1735             : 
    1736           0 :   void * _acct_in_use_copy = scratch;
    1737           0 :   void * _acct_in_use_orig = acct_uses_leave( pack->acct_in_use );
    1738           0 :   fd_memcpy( _acct_in_use_copy, _acct_in_use_orig, acct_uses_footprint( lg_uses_tbl_sz ) );
    1739             : 
    1740           0 :   fd_pack_addr_use_t * acct_in_use_copy = acct_uses_join( _acct_in_use_copy );
    1741             : 
    1742           0 :   FD_PACK_BITSET_DECLARE(  w_complement );
    1743           0 :   FD_PACK_BITSET_DECLARE( rw_complement );
    1744           0 :   FD_PACK_BITSET_COPY(  w_complement, full );
    1745           0 :   FD_PACK_BITSET_COPY( rw_complement, full );
    1746             : 
    1747           0 :   FD_PACK_BITSET_DECLARE( rw_bitset );  FD_PACK_BITSET_COPY( rw_bitset, pack->bitset_rw_in_use );
    1748           0 :   FD_PACK_BITSET_DECLARE(  w_bitset );  FD_PACK_BITSET_COPY(  w_bitset, pack->bitset_w_in_use  );
    1749             : 
    1750             : 
    1751           0 :   ulong const EMPTY_MASK = ~(FD_PACK_IN_USE_WRITABLE | FD_PACK_IN_USE_BIT_CLEARED);
    1752             : 
    1753           0 :   for( ulong bank=0UL; bank<pack->bank_tile_cnt; bank++ ) {
    1754             : 
    1755           0 :     fd_pack_addr_use_t const * base = pack->use_by_bank[ bank ];
    1756           0 :     ulong bank_mask = 1UL << bank;
    1757             : 
    1758           0 :     for( ulong i=0UL; i<pack->use_by_bank_cnt[ bank ]; i++ ) {
    1759           0 :       fd_pack_addr_use_t * use = acct_uses_query( acct_in_use_copy, base[i].key, NULL );
    1760           0 :       VERIFY_TEST( use, "acct in use by bank not in acct_in_use, or in uses_by_bank twice" );
    1761             : 
    1762           0 :       VERIFY_TEST( use->in_use_by & bank_mask, "acct in uses_by_bank doesn't have corresponding bit set in acct_in_use, or it was in the list twice" );
    1763             : 
    1764           0 :       fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, base[i].key, NULL );
    1765             :       /* The normal case is that the acct->bit mapping is preserved
    1766             :          while in use by other transactions in the pending list.  This
    1767             :          might not always happen though.  It's okay for the mapping to
    1768             :          get deleted while the acct is in use, which is noted with
    1769             :          BIT_CLEARED.  If that is set, the mapping may not exist, or it
    1770             :          may have been re-created, perhaps with a different bit. */
    1771           0 :       if( q==NULL ) VERIFY_TEST( use->in_use_by & FD_PACK_IN_USE_BIT_CLEARED, "acct in use not in acct_to_bitset, but not marked as cleared" );
    1772           0 :       else if( !(use->in_use_by & FD_PACK_IN_USE_BIT_CLEARED) ) {
    1773           0 :         FD_PACK_BITSET_CLEAR( bit );
    1774           0 :         FD_PACK_BITSET_SETN( bit, q->bit );
    1775           0 :         if( q->bit<FD_PACK_BITSET_MAX ) {
    1776           0 :           VERIFY_TEST( !FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, rw_bitset, rw_bitset ), "missing from rw bitset" );
    1777           0 :           if( use->in_use_by & FD_PACK_IN_USE_WRITABLE ) {
    1778           0 :             VERIFY_TEST( !FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, w_bitset, w_bitset ), "missing from w bitset" );
    1779           0 :             FD_PACK_BITSET_CLEARN( w_complement, q->bit );
    1780           0 :           }
    1781           0 :         }
    1782           0 :         FD_PACK_BITSET_CLEARN( rw_complement, q->bit );
    1783           0 :       }
    1784           0 :       if( use->in_use_by & FD_PACK_IN_USE_WRITABLE ) VERIFY_TEST( (use->in_use_by & EMPTY_MASK)==bank_mask, "writable, but in use by multiple" );
    1785             : 
    1786           0 :       use->in_use_by &= ~bank_mask;
    1787           0 :       if( !(use->in_use_by & EMPTY_MASK) ) acct_uses_remove( acct_in_use_copy, use );
    1788           0 :     }
    1789           0 :   }
    1790           0 :   VERIFY_TEST( acct_uses_key_cnt( acct_in_use_copy )==0UL, "stray uses in acct_in_use" );
    1791           0 :   VERIFY_TEST( FD_PACK_BITSET_INTERSECT4_EMPTY( rw_complement, rw_complement, rw_bitset,  rw_bitset ), "extra in rw bitset" );
    1792           0 :   VERIFY_TEST( FD_PACK_BITSET_INTERSECT4_EMPTY(  w_complement,  w_complement,  w_bitset,   w_bitset ), "extra in w bitset" );
    1793             : 
    1794           0 :   acct_uses_leave( acct_in_use_copy );
    1795             : 
    1796           0 :   acct_uses_join( _acct_in_use_orig );
    1797           0 :   return 0;
    1798           0 : }
    1799             : 
    1800           0 : void * fd_pack_leave ( fd_pack_t * pack ) { FD_COMPILER_MFENCE(); return (void *)pack; }
    1801           0 : void * fd_pack_delete( void      * mem  ) { FD_COMPILER_MFENCE(); return mem;          }

Generated by: LCOV version 1.14