LCOV - code coverage report
Current view: top level - ballet/pack - fd_pack.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 784 1033 75.9 %
Date: 2025-01-08 12:08:44 Functions: 17 25 68.0 %

          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             : /* FD_ORD_TXN_ROOT is essentially a small union packed into an int.  The low
      83             :    byte is the "tag".  The higher 3 bytes depend on the low byte. */
      84     4451358 : #define FD_ORD_TXN_ROOT_TAG_MASK        0xFF
      85     2671692 : #define FD_ORD_TXN_ROOT_FREE            0
      86    17998959 : #define FD_ORD_TXN_ROOT_PENDING         1
      87    13314177 : #define FD_ORD_TXN_ROOT_PENDING_VOTE    2
      88             : #define FD_ORD_TXN_ROOT_BUNDLE          3
      89      280418 : #define FD_ORD_TXN_ROOT_PENALTY( idx ) (4 | (idx)<<8)
      90             : 
      91             : /* if root & TAG_MASK == PENALTY, then PENALTY_ACCT_IDX(root) gives the index
      92             :    in the transaction's list of account addresses of which penalty treap the
      93             :    transaction is in. */
      94             : #define FD_ORD_TXN_ROOT_PENALTY_ACCT_IDX( root ) (((root) & 0xFF00)>>8)
      95             : 
      96             : 
      97    28372164 : #define FD_PACK_IN_USE_WRITABLE    (0x8000000000000000UL)
      98    15345687 : #define FD_PACK_IN_USE_BIT_CLEARED (0x4000000000000000UL)
      99             : 
     100             : /* Each non-empty microblock we schedule also has an overhead of 48
     101             :    bytes that counts towards shed limits.  That comes from the 32 byte
     102             :    hash, the hash count (8 bytes) and the transaction count (8 bytes).
     103             :    We don't have to pay this overhead if the microblock is empty, since
     104             :    those microblocks get dropped. */
     105     1476432 : #define MICROBLOCK_DATA_OVERHEAD 48UL
     106             : 
     107             : /* Keep track of accounts that are written to in each block so that we
     108             :    can reset the writer costs to 0.  If the number of accounts that are
     109             :    written to is above or equal to this, we'll just clear the whole
     110             :    writer cost map instead of only removing the elements we increased. */
     111        1344 : #define DEFAULT_WRITTEN_LIST_MAX 16384UL
     112             : 
     113             : /* fd_pack_addr_use_t: Used for two distinct purposes:
     114             :     -  to record that an address is in use and can't be used again until
     115             :          certain microblocks finish execution
     116             :     -  to keep track of the cost of all transactions that write to the
     117             :          specified account.
     118             :    Making these separate structs might make it more clear, but then
     119             :    they'd have identical shape and result in two fd_map_dynamic sets of
     120             :    functions with identical code.  It doesn't seem like the compiler is
     121             :    very good at merging code like that, so in order to reduce code
     122             :    bloat, we'll just combine them. */
     123             : struct fd_pack_private_addr_use_record {
     124             :   fd_acct_addr_t key; /* account address */
     125             :   union {
     126             :     ulong          in_use_by;  /* Bitmask indicating which banks */
     127             :     ulong          total_cost; /* In cost units/CUs */
     128             :   };
     129             : };
     130             : typedef struct fd_pack_private_addr_use_record fd_pack_addr_use_t;
     131             : 
     132             : 
     133             : /* fd_pack_sig_to_entry_t: An element of an fd_map that maps the first
     134             :    transaction signature to the corresponding fd_pack_ord_txn_t so that
     135             :    pending transactions can be deleted by signature.  Note: this
     136             :    implicitly relies on the fact that for Solana transactions the
     137             :    signature_offset is always 1.  If that fact changes, this will need
     138             :    to become a real struct. */
     139             : struct fd_pack_sig_to_txn {
     140             :   fd_ed25519_sig_t const * key;
     141             : };
     142             : typedef struct fd_pack_sig_to_txn fd_pack_sig_to_txn_t;
     143             : 
     144             : /* fd_pack_expq_t: An element of an fd_prq to sort the transactions by
     145             :    timeout.  This structure has several invariants for entries
     146             :    corresponding to pending transactions:
     147             :      expires_at == txn->expires_at
     148             :      txn->exp_prq_idx is the index of this structure
     149             :    Notice that prq is an array-based heap, which means the indexes of
     150             :    elements change.  The PRQ_TMP_ST macro is hijacked to keep that
     151             :    invariant up to date.
     152             : 
     153             :    Note: this could be easier if fd_heap supported deleting from the
     154             :    middle, but that's not possible with the current design of fd_heap,
     155             :    which omits a parent pointer for improved performance. */
     156             : struct fd_pack_expq {
     157             :   ulong               expires_at;
     158             :   fd_pack_ord_txn_t * txn;
     159             : };
     160             : typedef struct fd_pack_expq fd_pack_expq_t;
     161             : 
     162             : 
     163             : /* fd_pack_bitset_acct_mapping_t: An element of an fd_map_dynamic that
     164             :    maps an account address to the number of transactions that are
     165             :    referencing it and the bit that is reserved to indicate it in the
     166             :    bitset, if any. */
     167             : struct fd_pack_bitset_acct_mapping {
     168             :   fd_acct_addr_t key; /* account address */
     169             :   ulong          ref_cnt;
     170             : 
     171             :   /* first_instance and first_instance_was_write are only valid when
     172             :      bit==FD_PACK_BITSET_FIRST_INSTANCE, which is set when ref_cnt
     173             :      transitions from 0 to 1.  These just exist to implement the
     174             :      optimization that accounts referenced a single time aren't
     175             :      allocated a bit, but this seems to be an important optimization. */
     176             :   fd_pack_ord_txn_t * first_instance;
     177             :   int                 first_instance_was_write;
     178             : 
     179             :   /* bit is in [0, FD_PACK_BITSET_MAX) U
     180             :      { FD_PACK_BITSET_FIRST_INSTANCE, FD_PACK_BITSET_SLOWPATH }. */
     181             :   ushort              bit;
     182             : };
     183             : typedef struct fd_pack_bitset_acct_mapping fd_pack_bitset_acct_mapping_t;
     184             : 
     185             : /* Table of special addresses that are not allowed to be written to.  We
     186             :    immediately reject and refuse to pack any transaction that tries to
     187             :    write to one of these accounts.  Because we reject any writes to any
     188             :    of these accounts, we actually don't need to track reads of them
     189             :    either.  This is nice, because fd_map_dynamic requires a null address
     190             :    that we promise never to insert.  The zero address is a sysvar, so
     191             :    now we meet that part of the fd_map_dynamic contract. */
     192             : #define MAP_PERFECT_NAME      fd_pack_unwritable
     193             : #define MAP_PERFECT_LG_TBL_SZ 5
     194             : #define MAP_PERFECT_T         fd_acct_addr_t
     195    27378819 : #define MAP_PERFECT_HASH_C    1227063708U
     196             : #define MAP_PERFECT_KEY       b
     197             : #define MAP_PERFECT_KEY_T     fd_acct_addr_t const *
     198             : #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)
     199             : #define MAP_PERFECT_COMPLEX_KEY 1
     200    27378819 : #define MAP_PERFECT_KEYS_EQUAL(k1,k2) (!memcmp( (k1), (k2), 32UL ))
     201             : 
     202    27378819 : #define PERFECT_HASH( u ) (((MAP_PERFECT_HASH_C*(u))>>27)&0x1FU)
     203             : 
     204             : #define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \
     205             :                              a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \
     206             :                                           PERFECT_HASH( (a08 | (a09<<8) | (a10<<16) | (a11<<24)) )
     207    27378819 : #define MAP_PERFECT_HASH_R( ptr ) PERFECT_HASH( fd_uint_load_4( (uchar const *)ptr->b + 8UL ) )
     208             : 
     209             : /* This list is a superset of what Lab's is_builtin_key_or_sysvar checks. */
     210             : /* Sysvars */
     211             : #define MAP_PERFECT_0  ( SYSVAR_CLOCK_ID          ),
     212             : #define MAP_PERFECT_1  ( SYSVAR_EPOCH_SCHED_ID    ),
     213             : #define MAP_PERFECT_2  ( SYSVAR_FEES_ID           ),
     214             : #define MAP_PERFECT_3  ( SYSVAR_RECENT_BLKHASH_ID ),
     215             : #define MAP_PERFECT_4  ( SYSVAR_RENT_ID           ),
     216             : #define MAP_PERFECT_5  ( SYSVAR_REWARDS_ID        ),
     217             : #define MAP_PERFECT_6  ( SYSVAR_SLOT_HASHES_ID    ),
     218             : #define MAP_PERFECT_7  ( SYSVAR_SLOT_HIST_ID      ),
     219             : #define MAP_PERFECT_8  ( SYSVAR_STAKE_HIST_ID     ),
     220             : #define MAP_PERFECT_9  ( SYSVAR_INSTRUCTIONS_ID   ),
     221             : #define MAP_PERFECT_10 ( SYSVAR_EPOCH_REWARDS_ID  ),
     222             : #define MAP_PERFECT_11 ( SYSVAR_LAST_RESTART_ID   ),
     223             : /* Programs */
     224             : #define MAP_PERFECT_12 ( CONFIG_PROG_ID           ),
     225             : #define MAP_PERFECT_13 ( FEATURE_ID               ),
     226             : #define MAP_PERFECT_14 ( NATIVE_LOADER_ID         ),
     227             : #define MAP_PERFECT_15 ( STAKE_PROG_ID            ),
     228             : #define MAP_PERFECT_16 ( STAKE_CONFIG_PROG_ID     ),
     229             : #define MAP_PERFECT_17 ( VOTE_PROG_ID             ),
     230             : #define MAP_PERFECT_18 ( SYS_PROG_ID              ), /* Do not remove. See above. */
     231             : #define MAP_PERFECT_19 ( BPF_LOADER_1_PROG_ID     ),
     232             : #define MAP_PERFECT_20 ( BPF_LOADER_2_PROG_ID     ),
     233             : #define MAP_PERFECT_21 ( BPF_UPGRADEABLE_PROG_ID  ),
     234             : /* Extras */
     235             : #define MAP_PERFECT_22 ( ED25519_SV_PROG_ID       ),
     236             : #define MAP_PERFECT_23 ( KECCAK_SECP_PROG_ID      ),
     237             : #define MAP_PERFECT_24 ( COMPUTE_BUDGET_PROG_ID   ),
     238             : #define MAP_PERFECT_25 ( ADDR_LUT_PROG_ID         ),
     239             : #define MAP_PERFECT_26 ( NATIVE_MINT_ID           ),
     240             : #define MAP_PERFECT_27 ( TOKEN_PROG_ID            ),
     241             : #define MAP_PERFECT_28 ( SECP256R1_PROG_ID        ),
     242             : 
     243             : #include "../../util/tmpl/fd_map_perfect.c"
     244             : 
     245             : 
     246             : /* Returns 1 if x.rewards/x.compute < y.rewards/y.compute. Not robust. */
     247    87351100 : #define COMPARE_WORSE(x,y) ( ((ulong)((x)->rewards)*(ulong)((y)->compute_est)) < ((ulong)((y)->rewards)*(ulong)((x)->compute_est)) )
     248             : 
     249             : /* Declare all the data structures */
     250             : 
     251             : 
     252             : /* Define the big max-"heap" that we pull transactions off to schedule.
     253             :    The priority is given by reward/compute.  We may want to add in some
     254             :    additional terms at a later point.  In order to cheaply remove nodes,
     255             :    we actually use a treap.  */
     256             : #define POOL_NAME       trp_pool
     257        1557 : #define POOL_T          fd_pack_ord_txn_t
     258             : #define POOL_IDX_T      ushort
     259    29566008 : #define POOL_NEXT       parent
     260             : #include "../../util/tmpl/fd_pool.c"
     261             : 
     262             : #define TREAP_T         fd_pack_ord_txn_t
     263             : #define TREAP_NAME      treap
     264             : #define TREAP_QUERY_T   void *                                         /* We don't use query ... */
     265             : #define TREAP_CMP(a,b)  (__extension__({ (void)(a); (void)(b); -1; })) /* which means we don't need to give a real
     266             :                                                                           implementation to cmp either */
     267   179859686 : #define TREAP_IDX_T     ushort
     268             : #define TREAP_OPTIMIZE_ITERATION 1
     269    87351100 : #define TREAP_LT        COMPARE_WORSE
     270             : #include "../../util/tmpl/fd_treap.c"
     271             : 
     272             : 
     273             : /* Define a strange map where key and value are kind of the same
     274             :    variable.  Essentially, it maps the contents to which the pointer
     275             :    points to the value of the pointer. */
     276             : #define MAP_NAME              sig2txn
     277    40717962 : #define MAP_T                 fd_pack_sig_to_txn_t
     278   171452122 : #define MAP_KEY_T             fd_ed25519_sig_t const *
     279    36964170 : #define MAP_KEY_NULL          NULL
     280   171452122 : #define MAP_KEY_INVAL(k)      !(k)
     281             : #define MAP_MEMOIZE           0
     282   118171367 : #define MAP_KEY_EQUAL(k0,k1)  (((!!(k0))&(!!(k1)))&&(!memcmp((k0),(k1), FD_TXN_SIGNATURE_SZ)))
     283             : #define MAP_KEY_EQUAL_IS_SLOW 1
     284    66853244 : #define MAP_KEY_HASH(key)     fd_uint_load_4( (key) ) /* first 4 bytes of signature */
     285             : #include "../../util/tmpl/fd_map_dynamic.c"
     286             : 
     287             : 
     288             : static const fd_acct_addr_t null_addr = { 0 };
     289             : 
     290             : #define MAP_NAME              acct_uses
     291    94277589 : #define MAP_T                 fd_pack_addr_use_t
     292   111242472 : #define MAP_KEY_T             fd_acct_addr_t
     293   294536167 : #define MAP_KEY_NULL          null_addr
     294             : #if FD_HAS_AVX
     295   111242472 : # define MAP_KEY_INVAL(k)     _mm256_testz_si256( wb_ldu( (k).b ), wb_ldu( (k).b ) )
     296             : #else
     297             : # define MAP_KEY_INVAL(k)     MAP_KEY_EQUAL(k, null_addr)
     298             : #endif
     299    77297652 : #define MAP_KEY_EQUAL(k0,k1)  (!memcmp((k0).b,(k1).b, FD_TXN_ACCT_ADDR_SZ))
     300             : #define MAP_KEY_EQUAL_IS_SLOW 1
     301             : #define MAP_MEMOIZE           0
     302    94286028 : #define MAP_KEY_HASH(key)     ((uint)fd_ulong_hash( fd_ulong_load_8( (key).b ) ))
     303             : #include "../../util/tmpl/fd_map_dynamic.c"
     304             : 
     305             : 
     306             : #define MAP_NAME              bitset_map
     307    52297803 : #define MAP_T                 fd_pack_bitset_acct_mapping_t
     308    65613759 : #define MAP_KEY_T             fd_acct_addr_t
     309   872336525 : #define MAP_KEY_NULL          null_addr
     310             : #if FD_HAS_AVX
     311    65613759 : # define MAP_KEY_INVAL(k)     _mm256_testz_si256( wb_ldu( (k).b ), wb_ldu( (k).b ) )
     312             : #else
     313             : # define MAP_KEY_INVAL(k)     MAP_KEY_EQUAL(k, null_addr)
     314             : #endif
     315    39021783 : #define MAP_KEY_EQUAL(k0,k1)  (!memcmp((k0).b,(k1).b, FD_TXN_ACCT_ADDR_SZ))
     316             : #define MAP_KEY_EQUAL_IS_SLOW 1
     317             : #define MAP_MEMOIZE           0
     318    52324767 : #define MAP_KEY_HASH(key)     ((uint)fd_ulong_hash( fd_ulong_load_8( (key).b ) ))
     319             : #include "../../util/tmpl/fd_map_dynamic.c"
     320             : 
     321             : 
     322             : /* Since transactions can also expire, we also maintain a parallel
     323             :    priority queue.  This means elements are simultaneously part of the
     324             :    treap (ordered by priority) and the expiration queue (ordered by
     325             :    expiration).  It's tempting to use the priority field of the treap
     326             :    for this purpose, but that can result in degenerate treaps in some
     327             :    cases. */
     328             : #define PRQ_NAME             expq
     329    31794824 : #define PRQ_T                fd_pack_expq_t
     330    27128895 : #define PRQ_TIMEOUT_T        ulong
     331    27128895 : #define PRQ_TIMEOUT          expires_at
     332    15389927 : #define PRQ_TMP_ST(p,t)      do {                                   \
     333    15389927 :                                (p)[0] = (t);                        \
     334    15389927 :                                t.txn->expq_idx = (ulong)((p)-heap); \
     335    15389927 :                              } while( 0 )
     336             : #include "../../util/tmpl/fd_prq.c"
     337             : 
     338             : /* fd_pack_smallest: We want to keep track of the smallest transaction
     339             :    in each treap.  That way, if we know the amount of space left in the
     340             :    block is less than the smallest transaction in the heap, we can just
     341             :    skip the heap.  Since transactions can be deleted, etc. maintaining
     342             :    this precisely is hard, but we can maintain a conservative value
     343             :    fairly cheaply.  Since the CU limit or the byte limit can be the one
     344             :    that matters, we keep track of the smallest by both. */
     345             : struct fd_pack_smallest {
     346             :   ulong cus;
     347             :   ulong bytes;
     348             : };
     349             : typedef struct fd_pack_smallest fd_pack_smallest_t;
     350             : 
     351             : 
     352             : /* With realistic traffic patterns, we often see many, many transactions
     353             :    competing for the same writable account.  Since only one of these can
     354             :    execute at a time, we sometimes waste lots of scheduling time going
     355             :    through them one at a time.  To combat that, when a transaction
     356             :    writes to an account with more than PENALTY_TREAP_THRESHOLD
     357             :    references (readers or writers), instead of inserting it into the
     358             :    main treap, we insert it into a penalty treap for that specific hot
     359             :    account address.  These transactions are not immediately available
     360             :    for scheduling.  Then, when a transaction that writes to the hot
     361             :    address completes, we move the most lucrative transaction from the
     362             :    penalty treap to the main treap, making it available for scheduling.
     363             :    This policy may slightly violate the price-time priority scheduling
     364             :    approach pack normally uses: if the most lucrative transaction
     365             :    competing for hot state arrives after PENALTY_TREAP_THRESHOLD has
     366             :    been hit, it may be scheduled second instead of first.  However, if
     367             :    the account is in use at the time the new transaction arrives, it
     368             :    will be scheduled next, as desired.  This minor difference seems
     369             :    reasonable to reduce complexity.
     370             : 
     371             :    fd_pack_penalty_treap is one account-specific penalty treap.  All the
     372             :    transactions in the penalty_treap treap write to key.
     373             : 
     374             :    penalty_map is the fd_map_dynamic that maps accounts to their
     375             :    respective penalty treaps. */
     376             : struct fd_pack_penalty_treap {
     377             :         fd_acct_addr_t key;
     378             :         treap_t penalty_treap[1];
     379             : };
     380             : typedef struct fd_pack_penalty_treap fd_pack_penalty_treap_t;
     381             : 
     382             : #define MAP_NAME              penalty_map
     383     3685625 : #define MAP_T                 fd_pack_penalty_treap_t
     384     3686768 : #define MAP_KEY_T             fd_acct_addr_t
     385     6713541 : #define MAP_KEY_NULL          null_addr
     386             : #if FD_HAS_AVX
     387     3686768 : # define MAP_KEY_INVAL(k)     _mm256_testz_si256( wb_ldu( (k).b ), wb_ldu( (k).b ) )
     388             : #else
     389             : # define MAP_KEY_INVAL(k)     MAP_KEY_EQUAL(k, null_addr)
     390             : #endif
     391     3682406 : #define MAP_KEY_EQUAL(k0,k1)  (!memcmp((k0).b,(k1).b, FD_TXN_ACCT_ADDR_SZ))
     392             : #define MAP_KEY_EQUAL_IS_SLOW 1
     393             : #define MAP_MEMOIZE           0
     394     3684587 : #define MAP_KEY_HASH(key)     ((uint)fd_ulong_hash( fd_ulong_load_8( (key).b ) ))
     395             : #include "../../util/tmpl/fd_map_dynamic.c"
     396             : 
     397             : /* PENALTY_TREAP_THRESHOLD: How many references to an account do we
     398             :    allow before subsequent transactions that write to the account go to
     399             :    the penalty treap. */
     400    29488278 : #define PENALTY_TREAP_THRESHOLD 128UL
     401             : 
     402             : /* Finally, we can now declare the main pack data structure */
     403             : struct fd_pack_private {
     404             :   ulong      pack_depth;
     405             :   ulong      bank_tile_cnt;
     406             : 
     407             :   fd_pack_limits_t lim[1];
     408             : 
     409             :   ulong      pending_txn_cnt;
     410             :   ulong      microblock_cnt; /* How many microblocks have we
     411             :                                 generated in this block? */
     412             :   ulong      data_bytes_consumed; /* How much data is in this block so
     413             :                                      far ? */
     414             :   fd_rng_t * rng;
     415             : 
     416             :   ulong      cumulative_block_cost;
     417             :   ulong      cumulative_vote_cost;
     418             : 
     419             :   /* expire_before: Any transactions with expires_at strictly less than
     420             :      the current expire_before are removed from the available pending
     421             :      transaction.  Here, "expire" is used as a verb: cause all
     422             :      transactions before this time to expire. */
     423             :   ulong      expire_before;
     424             : 
     425             :   /* outstanding_microblock_mask: a bitmask indicating which banking
     426             :      tiles have outstanding microblocks, i.e. fd_pack has generated a
     427             :      microblock for that banking tile and the banking tile has not yet
     428             :      notified fd_pack that it has completed it. */
     429             :   ulong      outstanding_microblock_mask;
     430             : 
     431             :   /* The actual footprint for the pool and maps is allocated
     432             :      in the same order in which they are declared immediately following
     433             :      the struct.  I.e. these pointers point to memory not far after the
     434             :      struct.  The trees are just pointers into the pool so don't take up
     435             :      more space. */
     436             : 
     437             :   fd_pack_ord_txn_t * pool;
     438             : 
     439             :   /* Treaps (sorted by priority) of pending transactions.  We store the
     440             :      pending simple votes separately. */
     441             :   treap_t pending[1];
     442             :   treap_t pending_votes[1];
     443             : 
     444             :   /* penalty_treaps: an fd_map_dynamic mapping hotly contended account
     445             :      addresses to treaps of transactions that write to them.  We try not
     446             :      to allow more than roughly PENALTY_TREAP_THRESHOLD transactions in
     447             :      the main treap that write to each account, though this is not
     448             :      exact. */
     449             :   fd_pack_penalty_treap_t * penalty_treaps;
     450             : 
     451             :   /* pending{_votes}_smallest: keep a conservative estimate of the
     452             :      smallest transaction (by cost units and by bytes) in each heap.
     453             :      Both CUs and bytes should be set to ULONG_MAX is the treap is
     454             :      empty. */
     455             :   fd_pack_smallest_t pending_smallest[1];
     456             :   fd_pack_smallest_t pending_votes_smallest[1];
     457             : 
     458             :   /* expiration_q: At the same time that a transaction is in exactly one
     459             :      of the above treaps, it is also in the expiration queue, sorted by
     460             :      its expiration time.  This enables deleting all transactions that
     461             :      have expired, regardless of which treap they are in. */
     462             :   fd_pack_expq_t * expiration_q;
     463             : 
     464             :   /* acct_in_use: Map from account address to bitmask indicating which
     465             :      bank tiles are using the account and whether that use is read or
     466             :      write (msb). */
     467             :   fd_pack_addr_use_t   * acct_in_use;
     468             : 
     469             :   /* bitset_{w, rw}_in_use stores a subset of the information in
     470             :      acct_in_use using the compressed set format explained at the top of
     471             :      this file.  rw_in_use stores accounts in use for read or write
     472             :      while w_in_use stores only those in use for write. */
     473             :   FD_PACK_BITSET_DECLARE( bitset_rw_in_use );
     474             :   FD_PACK_BITSET_DECLARE( bitset_w_in_use  );
     475             : 
     476             :   /* writer_costs: Map from account addresses to the sum of costs of
     477             :      transactions that write to the account.  Used for enforcing limits
     478             :      on the max write cost per account per block. */
     479             :   fd_pack_addr_use_t   * writer_costs;
     480             : 
     481             :   /* At the end of every slot, we have to clear out writer_costs.  The
     482             :      map is large, but typically very sparsely populated.  As an
     483             :      optimization, we keep track of the elements of the map that we've
     484             :      actually used, up to a maximum.  If we use more than the maximum,
     485             :      we revert to the old way of just clearing the whole map.
     486             : 
     487             :      written_list indexed [0, written_list_cnt).
     488             :      written_list_cnt in  [0, written_list_max).
     489             : 
     490             :      written_list_cnt==written_list_max-1 means that the list may be
     491             :      incomplete and should be ignored. */
     492             :   fd_pack_addr_use_t * * written_list;
     493             :   ulong                  written_list_cnt;
     494             :   ulong                  written_list_max;
     495             : 
     496             : 
     497             :   fd_pack_sig_to_txn_t * signature_map; /* Stores pointers into pool for deleting by signature */
     498             : 
     499             :   /* use_by_bank: An array of size (max_txn_per_microblock *
     500             :      FD_TXN_ACCT_ADDR_MAX) for each banking tile.  Only the MSB of
     501             :      in_use_by is relevant.  Addressed use_by_bank[i][j] where i is in
     502             :      [0, bank_tile_cnt) and j is in [0, use_by_bank_cnt[i]).  Used
     503             :      mostly for clearing the proper bits of acct_in_use when a
     504             :      microblock finishes.
     505             : 
     506             :      use_by_bank_txn: indexed [i][j], where i is in [0, bank_tile_cnt)
     507             :      and j is in [0, max_txn_per_microblock).  Transaction j in the
     508             :      microblock currently scheduled to bank i uses account addresses in
     509             :      use_by_bank[i][k] where k is in [0, use_by_bank[i][j]).  For
     510             :      example, if use_by_bank[i][0] = 2 and use_by_bank[i][1] = 3, then
     511             :      all the accounts that the first transaction in the outstanding
     512             :      microblock for bank 0 uses are contained in the set
     513             :                { use_by_bank[i][0], use_by_bank[i][1] },
     514             :      and all the accounts in the second transaction in the microblock
     515             :      are in the set
     516             :         { use_by_bank[i][0], use_by_bank[i][1], use_by_bank[i][2] }.
     517             :      Each transaction writes to at least one account (the fee payer)
     518             :      that no other transaction scheduled to the bank uses, which means
     519             :      that use_by_bank_txn[i][j] - use_by_bank_txn[i][j-1] >= 1 (with 0
     520             :      for use_by_bank_txn[i][-1]).  This means we can stop iterating when
     521             :      use_by_bank_txn[i][j] == use_by_bank_cnt[i].  */
     522             :   fd_pack_addr_use_t * use_by_bank    [ FD_PACK_MAX_BANK_TILES ];
     523             :   ulong                use_by_bank_cnt[ FD_PACK_MAX_BANK_TILES ];
     524             :   ulong *              use_by_bank_txn[ FD_PACK_MAX_BANK_TILES ];
     525             : 
     526             :   fd_histf_t txn_per_microblock [ 1 ];
     527             :   fd_histf_t vote_per_microblock[ 1 ];
     528             : 
     529             :   fd_histf_t scheduled_cus_per_block[ 1 ];
     530             :   fd_histf_t rebated_cus_per_block  [ 1 ];
     531             :   fd_histf_t net_cus_per_block      [ 1 ];
     532             :   ulong      cumulative_rebated_cus;
     533             : 
     534             :   /* use_bundles: if true (non-zero), allows the use of bundles, groups
     535             :      of transactions that are executed atomically with high priority */
     536             :   int        use_bundles;
     537             : 
     538             :   /* bitset_avail: a stack of which bits are not currently reserved and
     539             :      can be used to represent an account address.
     540             :      Indexed [0, bitset_avail_cnt].  Element 0 is fixed at
     541             :      FD_PACK_BITSET_SLOWPATH. */
     542             :   ushort bitset_avail[ 1UL+FD_PACK_BITSET_MAX ];
     543             :   ulong  bitset_avail_cnt;
     544             : 
     545             :   /* acct_to_bitset: an fd_map_dynamic that maps acct addresses to the
     546             :      reference count, which bit, etc. */
     547             :   fd_pack_bitset_acct_mapping_t * acct_to_bitset;
     548             : 
     549             :   /* chdkup: scratch memory chkdup needs for its internal processing */
     550             :   fd_chkdup_t chkdup[ 1 ];
     551             : };
     552             : 
     553             : typedef struct fd_pack_private fd_pack_t;
     554             : 
     555             : FD_STATIC_ASSERT( offsetof(fd_pack_t, pending_txn_cnt)==FD_PACK_PENDING_TXN_CNT_OFF, txn_cnt_off );
     556             : 
     557             : ulong
     558             : fd_pack_footprint( ulong                    pack_depth,
     559             :                    ulong                    bank_tile_cnt,
     560         306 :                    fd_pack_limits_t const * limits         ) {
     561         306 :   if( FD_UNLIKELY( (bank_tile_cnt==0) | (bank_tile_cnt>FD_PACK_MAX_BANK_TILES) ) ) return 0UL;
     562         306 :   if( FD_UNLIKELY( pack_depth<4UL ) ) return 0UL;
     563             : 
     564         306 :   ulong l;
     565         306 :   ulong max_acct_in_treap  = pack_depth * FD_TXN_ACCT_ADDR_MAX;
     566         306 :   ulong max_acct_in_flight = bank_tile_cnt * (FD_TXN_ACCT_ADDR_MAX * limits->max_txn_per_microblock + 1UL);
     567         306 :   ulong max_txn_in_flight  = bank_tile_cnt * limits->max_txn_per_microblock;
     568             : 
     569         306 :   ulong max_w_per_block    = fd_ulong_min( limits->max_cost_per_block / FD_PACK_COST_PER_WRITABLE_ACCT,
     570         306 :                                            limits->max_txn_per_microblock * limits->max_microblocks_per_block * FD_TXN_ACCT_ADDR_MAX );
     571         306 :   ulong written_list_max   = fd_ulong_min( max_w_per_block>>1, DEFAULT_WRITTEN_LIST_MAX );
     572             : 
     573             :   /* log base 2, but with a 2* so that the hash table stays sparse */
     574         306 :   int lg_uses_tbl_sz = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_flight                        ) );
     575         306 :   int lg_max_writers = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_w_per_block                           ) );
     576         306 :   int lg_depth       = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*pack_depth                                ) );
     577         306 :   int lg_acct_in_trp = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_treap                         ) );
     578         306 :   int lg_penalty_trp = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_treap/PENALTY_TREAP_THRESHOLD ) );
     579             : 
     580         306 :   l = FD_LAYOUT_INIT;
     581         306 :   l = FD_LAYOUT_APPEND( l, FD_PACK_ALIGN,       sizeof(fd_pack_t)                               );
     582         306 :   l = FD_LAYOUT_APPEND( l, trp_pool_align (),   trp_pool_footprint ( pack_depth+1UL           ) ); /* pool           */
     583         306 :   l = FD_LAYOUT_APPEND( l, penalty_map_align(), penalty_map_footprint( lg_penalty_trp         ) ); /* penalty_treaps */
     584         306 :   l = FD_LAYOUT_APPEND( l, expq_align     (),   expq_footprint     ( pack_depth+1UL           ) ); /* expiration prq */
     585         306 :   l = FD_LAYOUT_APPEND( l, acct_uses_align(),   acct_uses_footprint( lg_uses_tbl_sz           ) ); /* acct_in_use    */
     586         306 :   l = FD_LAYOUT_APPEND( l, acct_uses_align(),   acct_uses_footprint( lg_max_writers           ) ); /* writer_costs   */
     587         306 :   l = FD_LAYOUT_APPEND( l, 32UL,                sizeof(fd_pack_addr_use_t*)*written_list_max    ); /* written_list   */
     588         306 :   l = FD_LAYOUT_APPEND( l, sig2txn_align  (),   sig2txn_footprint  ( lg_depth                 ) ); /* signature_map  */
     589         306 :   l = FD_LAYOUT_APPEND( l, 32UL,                sizeof(fd_pack_addr_use_t)*max_acct_in_flight   ); /* use_by_bank    */
     590         306 :   l = FD_LAYOUT_APPEND( l, 32UL,                sizeof(ulong)*max_txn_in_flight                 ); /* use_by_bank_txn*/
     591         306 :   l = FD_LAYOUT_APPEND( l, bitset_map_align(),  bitset_map_footprint( lg_acct_in_trp          ) ); /* acct_to_bitset */
     592         306 :   return FD_LAYOUT_FINI( l, FD_PACK_ALIGN );
     593         306 : }
     594             : 
     595             : void *
     596             : fd_pack_new( void                   * mem,
     597             :              ulong                    pack_depth,
     598             :              ulong                    bank_tile_cnt,
     599             :              fd_pack_limits_t const * limits,
     600         519 :              fd_rng_t                * rng           ) {
     601             : 
     602         519 :   ulong max_acct_in_treap  = pack_depth * FD_TXN_ACCT_ADDR_MAX;
     603         519 :   ulong max_acct_in_flight = bank_tile_cnt * (FD_TXN_ACCT_ADDR_MAX * limits->max_txn_per_microblock + 1UL);
     604         519 :   ulong max_txn_in_flight  = bank_tile_cnt * limits->max_txn_per_microblock;
     605         519 :   ulong max_w_per_block    = fd_ulong_min( limits->max_cost_per_block / FD_PACK_COST_PER_WRITABLE_ACCT,
     606         519 :                                            limits->max_txn_per_microblock * limits->max_microblocks_per_block * FD_TXN_ACCT_ADDR_MAX );
     607         519 :   ulong written_list_max   = fd_ulong_min( max_w_per_block>>1, DEFAULT_WRITTEN_LIST_MAX );
     608             : 
     609             :   /* log base 2, but with a 2* so that the hash table stays sparse */
     610         519 :   int lg_uses_tbl_sz = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_flight ) );
     611         519 :   int lg_max_writers = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_w_per_block    ) );
     612         519 :   int lg_depth       = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*pack_depth         ) );
     613         519 :   int lg_acct_in_trp = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_treap  ) );
     614         519 :   int lg_penalty_trp = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_treap/PENALTY_TREAP_THRESHOLD ) );
     615             : 
     616         519 :   FD_SCRATCH_ALLOC_INIT( l, mem );
     617         519 :   fd_pack_t * pack    = FD_SCRATCH_ALLOC_APPEND( l,  FD_PACK_ALIGN,       sizeof(fd_pack_t)                             );
     618             :   /* The pool has one extra element that is used between insert_init and
     619             :      cancel/fini. */
     620         519 :   void * _pool        = FD_SCRATCH_ALLOC_APPEND( l,  trp_pool_align(),    trp_pool_footprint ( pack_depth+1UL         ) );
     621         519 :   void * _penalty_map = FD_SCRATCH_ALLOC_APPEND( l,  penalty_map_align(), penalty_map_footprint( lg_penalty_trp       ) );
     622         519 :   void * _expq        = FD_SCRATCH_ALLOC_APPEND( l,  expq_align(),        expq_footprint     ( pack_depth+1UL         ) );
     623         519 :   void * _uses        = FD_SCRATCH_ALLOC_APPEND( l,  acct_uses_align(),   acct_uses_footprint( lg_uses_tbl_sz         ) );
     624         519 :   void * _writer_cost = FD_SCRATCH_ALLOC_APPEND( l,  acct_uses_align(),   acct_uses_footprint( lg_max_writers         ) );
     625         519 :   void * _written_lst = FD_SCRATCH_ALLOC_APPEND( l,  32UL,                sizeof(fd_pack_addr_use_t*)*written_list_max  );
     626         519 :   void * _sig_map     = FD_SCRATCH_ALLOC_APPEND( l,  sig2txn_align(),     sig2txn_footprint  ( lg_depth               ) );
     627         519 :   void * _use_by_bank = FD_SCRATCH_ALLOC_APPEND( l,  32UL,                sizeof(fd_pack_addr_use_t)*max_acct_in_flight );
     628         519 :   void * _use_by_txn  = FD_SCRATCH_ALLOC_APPEND( l,  32UL,                sizeof(ulong)*max_txn_in_flight               );
     629         519 :   void * _acct_bitset = FD_SCRATCH_ALLOC_APPEND( l,  bitset_map_align(),  bitset_map_footprint( lg_acct_in_trp        ) );
     630             : 
     631           0 :   pack->pack_depth                  = pack_depth;
     632         519 :   pack->bank_tile_cnt               = bank_tile_cnt;
     633         519 :   pack->lim[0]                      = *limits;
     634         519 :   pack->pending_txn_cnt             = 0UL;
     635         519 :   pack->microblock_cnt              = 0UL;
     636         519 :   pack->data_bytes_consumed         = 0UL;
     637         519 :   pack->rng                         = rng;
     638         519 :   pack->cumulative_block_cost       = 0UL;
     639         519 :   pack->cumulative_vote_cost        = 0UL;
     640         519 :   pack->expire_before               = 0UL;
     641         519 :   pack->outstanding_microblock_mask = 0UL;
     642         519 :   pack->cumulative_rebated_cus      = 0UL;
     643             : 
     644             : 
     645         519 :   trp_pool_new(  _pool,        pack_depth+1UL );
     646             : 
     647         519 :   fd_pack_ord_txn_t * pool = trp_pool_join( _pool );
     648         519 :   treap_seed( pool, pack_depth+1UL, fd_rng_ulong( rng ) );
     649     2177070 :   for( ulong i=0UL; i<pack_depth+1UL; i++ ) pool[i].root = FD_ORD_TXN_ROOT_FREE;
     650         519 :   (void)trp_pool_leave( pool );
     651             : 
     652         519 :   penalty_map_new( _penalty_map, lg_penalty_trp );
     653             : 
     654         519 :   treap_new( (void*)pack->pending,         pack_depth );
     655         519 :   treap_new( (void*)pack->pending_votes,   pack_depth );
     656             : 
     657         519 :   pack->pending_smallest->cus         = ULONG_MAX;
     658         519 :   pack->pending_smallest->bytes       = ULONG_MAX;
     659         519 :   pack->pending_votes_smallest->cus   = ULONG_MAX;
     660         519 :   pack->pending_votes_smallest->bytes = ULONG_MAX;
     661             : 
     662         519 :   expq_new( _expq, pack_depth+1UL );
     663             : 
     664         519 :   FD_PACK_BITSET_CLEAR( pack->bitset_rw_in_use );
     665         519 :   FD_PACK_BITSET_CLEAR( pack->bitset_w_in_use  );
     666             : 
     667         519 :   acct_uses_new( _uses,        lg_uses_tbl_sz );
     668         519 :   acct_uses_new( _writer_cost, lg_max_writers );
     669             : 
     670         519 :   pack->written_list     = _written_lst;
     671         519 :   pack->written_list_cnt = 0UL;
     672         519 :   pack->written_list_max = written_list_max;
     673             : 
     674         519 :   sig2txn_new(   _sig_map,     lg_depth       );
     675             : 
     676         519 :   fd_pack_addr_use_t * use_by_bank     = (fd_pack_addr_use_t *)_use_by_bank;
     677         519 :   ulong *              use_by_bank_txn = (ulong *)_use_by_txn;
     678        6765 :   for( ulong i=0UL; i<bank_tile_cnt; i++ ) {
     679        6246 :     pack->use_by_bank    [i] = use_by_bank + i*(FD_TXN_ACCT_ADDR_MAX*limits->max_txn_per_microblock+1UL);
     680        6246 :     pack->use_by_bank_cnt[i] = 0UL;
     681        6246 :     pack->use_by_bank_txn[i] = use_by_bank_txn + i*limits->max_txn_per_microblock;
     682        6246 :     pack->use_by_bank_txn[i][0] = 0UL;
     683        6246 :   }
     684       26451 :   for( ulong i=bank_tile_cnt; i<FD_PACK_MAX_BANK_TILES; i++ ) {
     685       25932 :     pack->use_by_bank    [i] = NULL;
     686       25932 :     pack->use_by_bank_cnt[i] = 0UL;
     687       25932 :     pack->use_by_bank_txn[i] = NULL;
     688       25932 :   }
     689             : 
     690         519 :   fd_histf_new( pack->txn_per_microblock,  FD_MHIST_MIN( PACK, TOTAL_TRANSACTIONS_PER_MICROBLOCK_COUNT ),
     691         519 :                                            FD_MHIST_MAX( PACK, TOTAL_TRANSACTIONS_PER_MICROBLOCK_COUNT ) );
     692         519 :   fd_histf_new( pack->vote_per_microblock, FD_MHIST_MIN( PACK, VOTES_PER_MICROBLOCK_COUNT ),
     693         519 :                                            FD_MHIST_MAX( PACK, VOTES_PER_MICROBLOCK_COUNT ) );
     694             : 
     695         519 :   fd_histf_new( pack->scheduled_cus_per_block, FD_MHIST_MIN( PACK, CUS_SCHEDULED ),
     696         519 :                                                FD_MHIST_MAX( PACK, CUS_SCHEDULED ) );
     697         519 :   fd_histf_new( pack->rebated_cus_per_block,   FD_MHIST_MIN( PACK, CUS_REBATED   ),
     698         519 :                                                FD_MHIST_MAX( PACK, CUS_REBATED   ) );
     699         519 :   fd_histf_new( pack->net_cus_per_block,       FD_MHIST_MIN( PACK, CUS_NET       ),
     700         519 :                                                FD_MHIST_MAX( PACK, CUS_NET       ) );
     701             : 
     702         519 :   pack->use_bundles = 0;
     703             : 
     704         519 :   pack->bitset_avail[ 0 ] = FD_PACK_BITSET_SLOWPATH;
     705      177671 :   for( ulong i=0UL; i<FD_PACK_BITSET_MAX; i++ ) pack->bitset_avail[ i+1UL ] = (ushort)i;
     706         519 :   pack->bitset_avail_cnt = FD_PACK_BITSET_MAX;
     707             : 
     708         519 :   bitset_map_new( _acct_bitset, lg_acct_in_trp );
     709             : 
     710         519 :   fd_chkdup_new( pack->chkdup, rng );
     711             : 
     712         519 :   return mem;
     713         519 : }
     714             : 
     715             : fd_pack_t *
     716         519 : fd_pack_join( void * mem ) {
     717         519 :   FD_SCRATCH_ALLOC_INIT( l, mem );
     718         519 :   fd_pack_t * pack  = FD_SCRATCH_ALLOC_APPEND( l, FD_PACK_ALIGN, sizeof(fd_pack_t) );
     719             : 
     720           0 :   ulong pack_depth             = pack->pack_depth;
     721         519 :   ulong bank_tile_cnt          = pack->bank_tile_cnt;
     722             : 
     723         519 :   ulong max_acct_in_treap  = pack_depth * FD_TXN_ACCT_ADDR_MAX;
     724         519 :   ulong max_acct_in_flight = bank_tile_cnt * (FD_TXN_ACCT_ADDR_MAX * pack->lim->max_txn_per_microblock + 1UL);
     725         519 :   ulong max_txn_in_flight  = bank_tile_cnt * pack->lim->max_txn_per_microblock;
     726         519 :   ulong max_w_per_block    = fd_ulong_min( pack->lim->max_cost_per_block / FD_PACK_COST_PER_WRITABLE_ACCT,
     727         519 :                                            pack->lim->max_txn_per_microblock * pack->lim->max_microblocks_per_block * FD_TXN_ACCT_ADDR_MAX );
     728         519 :   ulong written_list_max   = fd_ulong_min( max_w_per_block>>1, DEFAULT_WRITTEN_LIST_MAX );
     729             : 
     730         519 :   int lg_uses_tbl_sz = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_flight                        ) );
     731         519 :   int lg_max_writers = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_w_per_block                           ) );
     732         519 :   int lg_depth       = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*pack_depth                                ) );
     733         519 :   int lg_acct_in_trp = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_treap                         ) );
     734         519 :   int lg_penalty_trp = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_treap/PENALTY_TREAP_THRESHOLD ) );
     735             : 
     736             : 
     737         519 :   pack->pool          = trp_pool_join(   FD_SCRATCH_ALLOC_APPEND( l, trp_pool_align(),   trp_pool_footprint ( pack_depth+1UL ) ) );
     738         519 :   pack->penalty_treaps= penalty_map_join(FD_SCRATCH_ALLOC_APPEND( l, penalty_map_align(),penalty_map_footprint( lg_penalty_trp )));
     739         519 :   pack->expiration_q  = expq_join    (   FD_SCRATCH_ALLOC_APPEND( l, expq_align(),       expq_footprint     ( pack_depth+1UL ) ) );
     740         519 :   pack->acct_in_use   = acct_uses_join(  FD_SCRATCH_ALLOC_APPEND( l, acct_uses_align(),  acct_uses_footprint( lg_uses_tbl_sz ) ) );
     741         519 :   pack->writer_costs  = acct_uses_join(  FD_SCRATCH_ALLOC_APPEND( l, acct_uses_align(),  acct_uses_footprint( lg_max_writers ) ) );
     742         519 :   /* */                                  FD_SCRATCH_ALLOC_APPEND( l, 32UL,               sizeof(fd_pack_addr_use_t*)*written_list_max  );
     743         519 :   pack->signature_map = sig2txn_join(    FD_SCRATCH_ALLOC_APPEND( l, sig2txn_align(),    sig2txn_footprint  ( lg_depth       ) ) );
     744         519 :   /* */                                  FD_SCRATCH_ALLOC_APPEND( l, 32UL,               sizeof(fd_pack_addr_use_t)*max_acct_in_flight );
     745         519 :   /* */                                  FD_SCRATCH_ALLOC_APPEND( l, 32UL,               sizeof(ulong)*max_txn_in_flight         );
     746         519 :   pack->acct_to_bitset= bitset_map_join( FD_SCRATCH_ALLOC_APPEND( l, bitset_map_align(), bitset_map_footprint( lg_acct_in_trp) ) );
     747             : 
     748         519 :   FD_MGAUGE_SET( PACK, PENDING_TRANSACTIONS_HEAP_SIZE, pack_depth );
     749         519 :   return pack;
     750         519 : }
     751             : 
     752             : 
     753             : /* Returns 0 on failure, 1 on success for a vote, 2 on success for a
     754             :    non-vote. */
     755             : static int
     756             : fd_pack_estimate_rewards_and_compute( fd_txn_e_t        * txne,
     757    13572561 :                                       fd_pack_ord_txn_t * out ) {
     758    13572561 :   fd_txn_t * txn = TXN(txne->txnp);
     759    13572561 :   ulong sig_rewards = FD_PACK_FEE_PER_SIGNATURE * txn->signature_cnt; /* Easily in [5000, 635000] */
     760             : 
     761    13572561 :   ulong execution_cus;
     762    13572561 :   ulong adtl_rewards;
     763    13572561 :   ulong precompile_sigs;
     764    13572561 :   ulong cost = fd_pack_compute_cost( txn, txne->txnp->payload, &txne->txnp->flags, &execution_cus, &adtl_rewards, &precompile_sigs );
     765             : 
     766    13572561 :   if( FD_UNLIKELY( !cost ) ) return 0;
     767             : 
     768             :   /* precompile_sigs <= 16320, so after the addition,
     769             :      sig_rewards < 83,000,000 */
     770    13572558 :   sig_rewards += FD_PACK_FEE_PER_SIGNATURE * precompile_sigs;
     771             : 
     772             :   /* No fancy CU estimation in this version of pack
     773             :   for( ulong i=0UL; i<(ulong)txn->instr_cnt; i++ ) {
     774             :     uchar prog_id_idx = txn->instr[ i ].program_id;
     775             :     fd_acct_addr_t const * acct_addr = fd_txn_get_acct_addrs( txn, txnp->payload ) + (ulong)prog_id_idx;
     776             :   }
     777             :   */
     778    13572558 :   out->rewards                              = (adtl_rewards < (UINT_MAX - sig_rewards)) ? (uint)(sig_rewards + adtl_rewards) : UINT_MAX;
     779    13572558 :   out->compute_est                          = (uint)cost;
     780    13572558 :   out->txn->pack_cu.requested_execution_cus = (uint)execution_cus;
     781    13572558 :   out->txn->pack_cu.non_execution_cus       = (uint)(cost - execution_cus);
     782             : 
     783             : #if DETAILED_LOGGING
     784             :   FD_LOG_NOTICE(( "TXN estimated compute %lu+-%f. Rewards: %lu + %lu", compute_expected, (double)compute_variance, sig_rewards, adtl_rewards ));
     785             : #endif
     786             : 
     787    13572558 :   return fd_int_if( txne->txnp->flags & FD_TXN_P_FLAGS_IS_SIMPLE_VOTE, 1, 2 );
     788    13572561 : }
     789             : 
     790             : /* Can the fee payer afford to pay a transaction with the specified
     791             :    price?  Returns 1 if so, 0 otherwise.  This is just a stub that
     792             :    always returns 1 for now.  In general, this function can't be totally
     793             :    accurate, because the transactions immediately prior to this one can
     794             :    affect the balance of this fee payer, but a simple check here may be
     795             :    helpful for reducing spam. */
     796             : static int
     797             : fd_pack_can_fee_payer_afford( fd_acct_addr_t const * acct_addr,
     798    13572558 :                               ulong                  price /* in lamports */) {
     799    13572558 :   (void)acct_addr;
     800    13572558 :   (void)price;
     801    13572558 :   return 1;
     802    13572558 : }
     803             : 
     804             : 
     805             : 
     806             : 
     807             : 
     808    13694961 : fd_txn_e_t * fd_pack_insert_txn_init(   fd_pack_t * pack                   ) { return trp_pool_ele_acquire( pack->pool )->txn_e; }
     809      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 ); }
     810             : 
     811         111 : #define REJECT( reason ) do {                                       \
     812         111 :                            trp_pool_ele_release( pack->pool, ord ); \
     813         111 :                            return FD_PACK_INSERT_REJECT_ ## reason; \
     814         111 :                          } while( 0 )
     815             : 
     816      280418 : #define ACCT_IDX_TO_PTR( idx ) (__extension__( {                                               \
     817      280418 :       ulong __idx = (idx);                                                                     \
     818      280418 :       fd_ptr_if( __idx<fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM ), accts, alt_adj )+__idx; \
     819      280418 :       }))
     820    70608888 : #define ACCT_ITER_TO_PTR( iter ) (__extension__( {                                             \
     821    70608888 :       ulong __idx = fd_txn_acct_iter_idx( iter );                                              \
     822    70608888 :       fd_ptr_if( __idx<fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM ), accts, alt_adj )+__idx; \
     823    70608888 :       }))
     824             : 
     825             : int
     826             : fd_pack_insert_txn_fini( fd_pack_t  * pack,
     827             :                          fd_txn_e_t * txne,
     828    13572561 :                          ulong        expires_at ) {
     829             : 
     830    13572561 :   fd_pack_ord_txn_t * ord = (fd_pack_ord_txn_t *)txne;
     831             : 
     832    13572561 :   fd_txn_t * txn   = TXN(txne->txnp);
     833    13572561 :   uchar * payload  = txne->txnp->payload;
     834             : 
     835    13572561 :   fd_acct_addr_t const * accts   = fd_txn_get_acct_addrs( txn, payload );
     836             :   /* alt_adj is the pointer to the ALT expansion, adjusted so that if
     837             :      account address n is the first that comes from the ALT, it can be
     838             :      accessed with adj_lut[n]. */
     839    13572561 :   fd_acct_addr_t const * alt     = ord->txn_e->alt_accts;
     840    13572561 :   fd_acct_addr_t const * alt_adj = ord->txn_e->alt_accts - fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM );
     841    13572561 :   ulong imm_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM );
     842    13572561 :   ulong alt_cnt = fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_ALT );
     843             : 
     844    13572561 :   int est_result = fd_pack_estimate_rewards_and_compute( txne, ord );
     845    13572561 :   if( FD_UNLIKELY( !est_result ) ) REJECT( ESTIMATION_FAIL );
     846             : 
     847    13572558 :   ord->expires_at = expires_at;
     848    13572558 :   int is_vote = est_result==1;
     849             : 
     850    13572558 :   int writes_to_sysvar = 0;
     851    13572558 :   for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
     852    28316307 :       iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
     853    14743749 :     writes_to_sysvar |= fd_pack_unwritable_contains( ACCT_ITER_TO_PTR( iter ) );
     854    14743749 :   }
     855             : 
     856    13572558 :   int bundle_blacklist = 0;
     857    13572558 :   if( FD_UNLIKELY( pack->use_bundles ) ) {
     858           0 :     for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_ALL );
     859           0 :         iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
     860           0 :       bundle_blacklist |= fd_pack_tip_prog_check_blacklist( ACCT_ITER_TO_PTR( iter ) );
     861           0 :     }
     862           0 :   }
     863             : 
     864    13572558 :   fd_ed25519_sig_t const * sig = fd_txn_get_signatures( txn, payload );
     865    13572558 :   fd_chkdup_t * chkdup = pack->chkdup;
     866             : 
     867             :   /* Throw out transactions ... */
     868             :   /*           ... that are unfunded */
     869    13572558 :   if( FD_UNLIKELY( !fd_pack_can_fee_payer_afford( accts, ord->rewards    ) ) ) REJECT( UNAFFORDABLE     );
     870             :   /*           ... that are so big they'll never run */
     871    13572558 :   if( FD_UNLIKELY( ord->compute_est >= pack->lim->max_cost_per_block       ) ) REJECT( TOO_LARGE        );
     872             :   /*           ... that load too many accounts (ignoring 9LZdXeKGeBV6hRLdxS1rHbHoEUsKqesCC2ZAPTPKJAbK) */
     873    13572558 :   if( FD_UNLIKELY( fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_ALL )>64UL     ) ) REJECT( ACCOUNT_CNT      );
     874             :   /*           ... that duplicate an account address */
     875    13572555 :   if( FD_UNLIKELY( fd_chkdup_check( chkdup, accts, imm_cnt, alt, alt_cnt ) ) ) REJECT( DUPLICATE_ACCT   );
     876             :   /*           ... that try to write to a sysvar */
     877    13572552 :   if( FD_UNLIKELY( writes_to_sysvar                                        ) ) REJECT( WRITES_SYSVAR    );
     878             :   /*           ... that we already know about */
     879    13572465 :   if( FD_UNLIKELY( sig2txn_query( pack->signature_map, sig, NULL         ) ) ) REJECT( DUPLICATE        );
     880             :   /*           ... that have already expired */
     881    13572462 :   if( FD_UNLIKELY( expires_at<pack->expire_before                          ) ) REJECT( EXPIRED          );
     882             :   /*           ... that use an account that violates bundle rules */
     883    13572450 :   if( FD_UNLIKELY( bundle_blacklist & 1                                    ) ) REJECT( BUNDLE_BLACKLIST );
     884             : 
     885             : 
     886    13572450 :   int replaces = 0;
     887    13572450 :   if( FD_UNLIKELY( pack->pending_txn_cnt == pack->pack_depth ) ) {
     888             :     /* If the tree is full, we want to see if this is better than the
     889             :        worst element in the pool before inserting.  If the new
     890             :        transaction is better than that one, we'll delete it and insert
     891             :        the new transaction. Otherwise, we'll throw away this
     892             :        transaction.
     893             : 
     894             :        We want to bias the definition of "worst" here to provide better
     895             :        quality of service.  For example, if the pool is filled with
     896             :        transactions that all write to the same account or are all votes,
     897             :        we want to bias towards treating one of those transactions as the
     898             :        worst, even if they pay slightly higher fees per computer unit,
     899             :        since we know we won't actually be able to schedule them all.
     900             : 
     901             :        This is a tricky task, however.  All our notions of priority and
     902             :        better/worse are based on static information about the
     903             :        transaction, and there's not an easy way to take into account
     904             :        global information, for example, how many other transactions
     905             :        contend with this one.  One idea is to build a heap (not a treap,
     906             :        since we only need pop-min, insert, and delete) with one element
     907             :        for each element in the pool, with a "delete me" score that's
     908             :        related but not identical to the normal score.  This would allow
     909             :        building in some global information.  The downside is that the
     910             :        global information that gets integrated is static.  E.g. if you
     911             :        bias a transaction's "delete me" score to make it more likely to
     912             :        be deleted because there are many conflicting transactions in the
     913             :        pool, the score stays biased, even if the global conditions
     914             :        change (unless you come up with some complicated re-scoring
     915             :        scheme).  This can work, since when the pool is full, the global
     916             :        bias factors are unlikely to change significantly at the relevant
     917             :        timescales.
     918             : 
     919             :        However, rather than this, we implement a simpler probabilistic
     920             :        scheme.  We'll sample M transactions, find the worst transaction
     921             :        in each of the M treaps, compute a "delete me" score for those
     922             :        <= M transactions, and delete the worst.  If one penalty treap is
     923             :        starting to get big, then it becomes very likely that the random
     924             :        sample will find it and choose to delete a transaction from it.
     925             : 
     926             :        The exact formula for the "delete me" score should be the matter
     927             :        of some more intense quantitative research.  For now, we'll just
     928             :        use this:
     929             : 
     930             :          Treap with N transactions        Scale Factor
     931             :             Pending                      1.0 unless inserting a vote and votes < 25%
     932             :             Pending votes                1.0 until 75% of depth, then 0
     933             :             Penalty treap                1.0 at <= 100 transactions, then sqrt(100/N)
     934             : 
     935             :        We'll also use M=8. */
     936      494592 :     float worst_score = FLT_MAX;
     937      494592 :     fd_pack_ord_txn_t * worst = NULL;
     938     4451328 :     for( ulong i=0UL; i<8UL; i++ ) {
     939     3956736 :       ulong sample_i = fd_rng_uint_roll( pack->rng, (uint)(pack->pack_depth+1UL) );
     940             : 
     941     3956736 :       fd_pack_ord_txn_t * sample = &pack->pool[ sample_i ];
     942             :       /* There is exactly one free one, the one that's currently being
     943             :          inserted, so we can choose it with probability 1/(depth+1),
     944             :          which is small.  If it does happen, just take the previous one,
     945             :          unless there isn't one. */
     946     3956736 :       if( FD_UNLIKELY( sample->root==FD_ORD_TXN_ROOT_FREE ) ) sample += fd_int_if( sample_i==0UL, 1, -1 );
     947             : 
     948     3956736 :       int       root_idx = sample->root;
     949     3956736 :       float     score    = 0.0f;
     950     3956736 :       switch( root_idx & FD_ORD_TXN_ROOT_TAG_MASK ) {
     951           0 :         case FD_ORD_TXN_ROOT_FREE: {
     952           0 :           FD_TEST( 0 );
     953           0 :           break;
     954           0 :         }
     955     3937295 :         case FD_ORD_TXN_ROOT_PENDING: {
     956     3937295 :           ulong vote_cnt = treap_ele_cnt( pack->pending_votes );
     957     3937295 :           if( FD_LIKELY( !is_vote || (vote_cnt>=pack->pack_depth/4UL ) ) ) score = (float)sample->rewards / (float)sample->compute_est;
     958     3937295 :           break;
     959           0 :         }
     960           0 :         case FD_ORD_TXN_ROOT_PENDING_VOTE: {
     961           0 :           ulong vote_cnt = treap_ele_cnt( pack->pending_votes );
     962           0 :           if( FD_LIKELY( is_vote || (vote_cnt<=3UL*pack->pack_depth/4UL ) ) ) score = (float)sample->rewards / (float)sample->compute_est;
     963           0 :           break;
     964           0 :         }
     965       19441 :         case FD_ORD_TXN_ROOT_PENALTY( 0 ): {
     966       19441 :           fd_txn_t * txn = TXN( sample->txn );
     967       19441 :           fd_acct_addr_t const * accts   = fd_txn_get_acct_addrs( txn, sample->txn->payload );
     968       19441 :           fd_acct_addr_t const * alt_adj = sample->txn_e->alt_accts - fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM );
     969       19441 :           fd_acct_addr_t penalty_acct = *ACCT_IDX_TO_PTR( FD_ORD_TXN_ROOT_PENALTY_ACCT_IDX( root_idx ) );
     970       19441 :           fd_pack_penalty_treap_t * q = penalty_map_query( pack->penalty_treaps, penalty_acct, NULL );
     971       19441 :           FD_TEST( q );
     972       19441 :           ulong cnt = treap_ele_cnt( q->penalty_treap );
     973       19441 :           score = (float)sample->rewards / (float)sample->compute_est * sqrtf( 100.0f / (float)cnt );
     974       19441 :           break;
     975       19441 :         }
     976     3956736 :       }
     977     3956736 :       worst = fd_ptr_if( score<worst_score, sample, worst );
     978     3956736 :       worst_score = fd_float_if( worst_score<score, worst_score, score );
     979     3956736 :     }
     980             : 
     981      494592 :     float incoming_score = (float)ord->rewards / (float)ord->compute_est;
     982      494592 :     if( FD_UNLIKELY( incoming_score<worst_score ) ) REJECT( PRIORITY );
     983             : 
     984      494592 :     replaces = 1;
     985      494592 :     fd_ed25519_sig_t const * worst_sig = fd_txn_get_signatures( TXN( worst->txn ), worst->txn->payload );
     986      494592 :     fd_pack_delete_transaction( pack, worst_sig );
     987      494592 :   }
     988             : 
     989             : 
     990             :   /* At this point, we know we have space to insert the transaction and
     991             :      we've committed to insert it. */
     992             : 
     993    13572450 :   FD_PACK_BITSET_CLEAR( ord->rw_bitset );
     994    13572450 :   FD_PACK_BITSET_CLEAR( ord->w_bitset  );
     995             : 
     996    13572450 :   ulong  cumulative_penalty = 0UL;
     997    13572450 :   ulong  penalty_i          = 0UL;
     998             :   /* Since the pool uses ushorts, the size of the pool is < USHORT_MAX.
     999             :      Each transaction can reference an account at most once, which means
    1000             :      that the total number of references for an account is < USHORT_MAX.
    1001             :      If these were ulongs, the array would be 512B, which is kind of a
    1002             :      lot to zero out.*/
    1003    13572450 :   ushort penalties[ FD_TXN_ACCT_ADDR_MAX ] = {0};
    1004    13572450 :   uchar  penalty_idx[ FD_TXN_ACCT_ADDR_MAX ];
    1005             : 
    1006    13572450 :   for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
    1007    28315917 :       iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1008    14743467 :     fd_acct_addr_t acct = *ACCT_ITER_TO_PTR( iter );
    1009    14743467 :     fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, acct, NULL );
    1010    14743467 :     if( FD_UNLIKELY( q==NULL ) ) {
    1011    13258728 :       q = bitset_map_insert( pack->acct_to_bitset, acct );
    1012    13258728 :       q->ref_cnt                  = 0UL;
    1013    13258728 :       q->first_instance           = ord;
    1014    13258728 :       q->first_instance_was_write = 1;
    1015    13258728 :       q->bit                      = FD_PACK_BITSET_FIRST_INSTANCE;
    1016    13258728 :     } else if( FD_UNLIKELY( q->bit == FD_PACK_BITSET_FIRST_INSTANCE ) ) {
    1017        5979 :       q->bit = pack->bitset_avail[ pack->bitset_avail_cnt ];
    1018        5979 :       pack->bitset_avail_cnt = fd_ulong_if( !!pack->bitset_avail_cnt, pack->bitset_avail_cnt-1UL, 0UL );
    1019             : 
    1020        5979 :       FD_PACK_BITSET_SETN( q->first_instance->rw_bitset, q->bit );
    1021        5979 :       if( q->first_instance_was_write ) FD_PACK_BITSET_SETN( q->first_instance->w_bitset, q->bit );
    1022        5979 :     }
    1023    14743467 :     ulong penalty = fd_ulong_max( q->ref_cnt, PENALTY_TREAP_THRESHOLD )-PENALTY_TREAP_THRESHOLD;
    1024    14743467 :     if( FD_UNLIKELY( penalty ) ) {
    1025     1030398 :       penalties  [ penalty_i ] = (ushort)penalty;
    1026     1030398 :       penalty_idx[ penalty_i ] = (uchar )fd_txn_acct_iter_idx( iter );
    1027     1030398 :       penalty_i++;
    1028     1030398 :       cumulative_penalty += penalty;
    1029     1030398 :     }
    1030             : 
    1031    14743467 :     q->ref_cnt++;
    1032    14743467 :     FD_PACK_BITSET_SETN( ord->rw_bitset, q->bit );
    1033    14743467 :     FD_PACK_BITSET_SETN( ord->w_bitset , q->bit );
    1034    14743467 :   }
    1035             : 
    1036    13572450 :   for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY );
    1037    18118134 :       iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1038             : 
    1039     4545684 :     fd_acct_addr_t acct = *ACCT_ITER_TO_PTR( iter );
    1040     4545684 :     if( FD_UNLIKELY( fd_pack_unwritable_contains( &acct ) ) ) continue;
    1041             : 
    1042     3063162 :     fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, acct, NULL );
    1043     3063162 :     if( FD_UNLIKELY( q==NULL ) ) {
    1044       23727 :       q = bitset_map_insert( pack->acct_to_bitset, acct );
    1045       23727 :       q->ref_cnt                  = 0UL;
    1046       23727 :       q->first_instance           = ord;
    1047       23727 :       q->first_instance_was_write = 0;
    1048       23727 :       q->bit                      = FD_PACK_BITSET_FIRST_INSTANCE;
    1049     3039435 :     } else if( FD_UNLIKELY( q->bit == FD_PACK_BITSET_FIRST_INSTANCE ) ) {
    1050       10632 :       q->bit = pack->bitset_avail[ pack->bitset_avail_cnt ];
    1051       10632 :       pack->bitset_avail_cnt = fd_ulong_if( !!pack->bitset_avail_cnt, pack->bitset_avail_cnt-1UL, 0UL );
    1052             : 
    1053       10632 :       FD_PACK_BITSET_SETN( q->first_instance->rw_bitset, q->bit );
    1054       10632 :       if( q->first_instance_was_write ) FD_PACK_BITSET_SETN( q->first_instance->w_bitset, q->bit );
    1055       10632 :     }
    1056             : 
    1057     3063162 :     q->ref_cnt++;
    1058     3063162 :     FD_PACK_BITSET_SETN( ord->rw_bitset, q->bit );
    1059     3063162 :   }
    1060             : 
    1061    13572450 :   treap_t * insert_into = pack->pending;
    1062             : 
    1063    13572450 :   if( FD_UNLIKELY( cumulative_penalty && !is_vote ) ) { /* Optimize for high parallelism case */
    1064             :     /* Compute a weighted random choice */
    1065      258273 :     ulong roll = (ulong)fd_rng_uint_roll( pack->rng, (uint)cumulative_penalty ); /* cumulative_penalty < USHORT_MAX*64 < UINT_MAX */
    1066      258273 :     ulong i = 0UL;
    1067             :     /* Find the right one.  This can be done in O(log N), but I imagine
    1068             :        N is normally so small that doesn't matter. */
    1069      643976 :     while( roll>=penalties[i] ) roll -= (ulong)penalties[i++];
    1070             : 
    1071      258273 :     fd_acct_addr_t penalty_acct = *ACCT_IDX_TO_PTR( penalty_idx[i] );
    1072      258273 :     fd_pack_penalty_treap_t * q = penalty_map_query( pack->penalty_treaps, penalty_acct, NULL );
    1073      258273 :     if( FD_UNLIKELY( q==NULL ) ) {
    1074        2181 :       q = penalty_map_insert( pack->penalty_treaps, penalty_acct );
    1075        2181 :       treap_new( q->penalty_treap, pack->pack_depth );
    1076        2181 :     }
    1077      258273 :     insert_into = q->penalty_treap;
    1078      258273 :     ord->root = FD_ORD_TXN_ROOT_PENALTY( penalty_idx[i] );
    1079    13314177 :   } else {
    1080    13314177 :     ord->root = fd_int_if( is_vote, FD_ORD_TXN_ROOT_PENDING_VOTE, FD_ORD_TXN_ROOT_PENDING );
    1081             : 
    1082    13314177 :     fd_pack_smallest_t * smallest = fd_ptr_if( is_vote, &pack->pending_votes_smallest[0], pack->pending_smallest );
    1083    13314177 :     smallest->cus   = fd_ulong_min( smallest->cus,   ord->compute_est       );
    1084    13314177 :     smallest->bytes = fd_ulong_min( smallest->bytes, txne->txnp->payload_sz );
    1085    13314177 :   }
    1086             : 
    1087    13572450 :   pack->pending_txn_cnt++;
    1088             : 
    1089    13572450 :   sig2txn_insert( pack->signature_map, fd_txn_get_signatures( txn, payload ) );
    1090             : 
    1091    13572450 :   fd_pack_expq_t temp[ 1 ] = {{ .expires_at = expires_at, .txn = ord }};
    1092    13572450 :   expq_insert( pack->expiration_q, temp );
    1093             : 
    1094    13572450 :   if( FD_LIKELY( is_vote ) ) {
    1095       37596 :     treap_ele_insert( pack->pending_votes, ord, pack->pool );
    1096       37596 :     return replaces ? FD_PACK_INSERT_ACCEPT_VOTE_REPLACE : FD_PACK_INSERT_ACCEPT_VOTE_ADD;
    1097    13534854 :   } else {
    1098    13534854 :     treap_ele_insert( insert_into,         ord, pack->pool );
    1099    13534854 :     return replaces ? FD_PACK_INSERT_ACCEPT_NONVOTE_REPLACE : FD_PACK_INSERT_ACCEPT_NONVOTE_ADD;
    1100    13534854 :   }
    1101    13572450 : }
    1102             : #undef REJECT
    1103             : 
    1104             : void
    1105           0 : fd_pack_metrics_write( fd_pack_t const * pack ) {
    1106           0 :   ulong pending_votes = treap_ele_cnt( pack->pending_votes );
    1107           0 :   FD_MGAUGE_SET( PACK, AVAILABLE_TRANSACTIONS,       pack->pending_txn_cnt                                                  );
    1108           0 :   FD_MGAUGE_SET( PACK, AVAILABLE_VOTE_TRANSACTIONS,  pending_votes                                                          );
    1109           0 :   FD_MGAUGE_SET( PACK, CONFLICTING_TRANSACTIONS,     pack->pending_txn_cnt - treap_ele_cnt( pack->pending ) - pending_votes );
    1110           0 :   FD_MGAUGE_SET( PACK, SMALLEST_PENDING_TRANSACTION, pack->pending_smallest->cus                                            );
    1111           0 : }
    1112             : 
    1113             : typedef struct {
    1114             :   ushort clear_rw_bit;
    1115             :   ushort clear_w_bit;
    1116             : } release_result_t;
    1117             : 
    1118             : static inline release_result_t
    1119             : release_bit_reference( fd_pack_t            * pack,
    1120    17805693 :                        fd_acct_addr_t const * acct ) {
    1121             : 
    1122    17805693 :   fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, *acct, NULL );
    1123    17805693 :   FD_TEST( q ); /* q==NULL not be possible */
    1124             : 
    1125    17805693 :   q->ref_cnt--;
    1126             : 
    1127    17805693 :   if( FD_UNLIKELY( q->ref_cnt==0UL ) ) {
    1128    13281519 :     ushort bit = q->bit;
    1129    13281519 :     bitset_map_remove( pack->acct_to_bitset, q );
    1130    13281519 :     if( FD_LIKELY( bit<FD_PACK_BITSET_MAX ) ) pack->bitset_avail[ ++(pack->bitset_avail_cnt) ] = bit;
    1131             : 
    1132    13281519 :     fd_pack_addr_use_t * use = acct_uses_query( pack->acct_in_use,  *acct, NULL );
    1133    13281519 :     if( FD_LIKELY( use ) ) {
    1134    12787101 :       use->in_use_by |= FD_PACK_IN_USE_BIT_CLEARED;
    1135    12787101 :       release_result_t ret = { .clear_rw_bit = bit,
    1136    12787101 :                                .clear_w_bit = fd_ushort_if( !!(use->in_use_by & FD_PACK_IN_USE_WRITABLE), bit, FD_PACK_BITSET_MAX ) };
    1137    12787101 :       return ret;
    1138    12787101 :     }
    1139    13281519 :   }
    1140     5018592 :   release_result_t ret = { .clear_rw_bit = FD_PACK_BITSET_MAX, .clear_w_bit = FD_PACK_BITSET_MAX };
    1141     5018592 :   return ret;
    1142    17805693 : }
    1143             : 
    1144             : typedef struct {
    1145             :   ulong cus_scheduled;
    1146             :   ulong txns_scheduled;
    1147             :   ulong bytes_scheduled;
    1148             : } sched_return_t;
    1149             : 
    1150             : static inline sched_return_t
    1151             : fd_pack_schedule_impl( fd_pack_t          * pack,
    1152             :                        treap_t            * sched_from,
    1153             :                        ulong                cu_limit,
    1154             :                        ulong                txn_limit,
    1155             :                        ulong                byte_limit,
    1156             :                        ulong                bank_tile,
    1157             :                        fd_pack_smallest_t * smallest_in_treap,
    1158             :                        ulong              * use_by_bank_txn,
    1159     1476432 :                        fd_txn_p_t         * out ) {
    1160             : 
    1161     1476432 :   fd_pack_ord_txn_t  * pool         = pack->pool;
    1162     1476432 :   fd_pack_addr_use_t * acct_in_use  = pack->acct_in_use;
    1163     1476432 :   fd_pack_addr_use_t * writer_costs = pack->writer_costs;
    1164             : 
    1165     1476432 :   fd_pack_addr_use_t ** written_list     = pack->written_list;
    1166     1476432 :   ulong                 written_list_cnt = pack->written_list_cnt;
    1167     1476432 :   ulong                 written_list_max = pack->written_list_max;
    1168             : 
    1169     1476432 :   FD_PACK_BITSET_DECLARE( bitset_rw_in_use );
    1170     1476432 :   FD_PACK_BITSET_DECLARE( bitset_w_in_use  );
    1171     1476432 :   FD_PACK_BITSET_COPY( bitset_rw_in_use, pack->bitset_rw_in_use );
    1172     1476432 :   FD_PACK_BITSET_COPY( bitset_w_in_use,  pack->bitset_w_in_use  );
    1173             : 
    1174     1476432 :   fd_pack_addr_use_t * use_by_bank     = pack->use_by_bank    [bank_tile];
    1175     1476432 :   ulong                use_by_bank_cnt = pack->use_by_bank_cnt[bank_tile];
    1176             : 
    1177     1476432 :   ulong max_write_cost_per_acct = pack->lim->max_write_cost_per_acct;
    1178             : 
    1179     1476432 :   ulong txns_scheduled  = 0UL;
    1180     1476432 :   ulong cus_scheduled   = 0UL;
    1181     1476432 :   ulong bytes_scheduled = 0UL;
    1182             : 
    1183     1476432 :   ulong bank_tile_mask = 1UL << bank_tile;
    1184             : 
    1185     1476432 :   ulong fast_path     = 0UL;
    1186     1476432 :   ulong slow_path     = 0UL;
    1187     1476432 :   ulong cu_limit_c    = 0UL;
    1188     1476432 :   ulong byte_limit_c  = 0UL;
    1189     1476432 :   ulong write_limit_c = 0UL;
    1190             : 
    1191     1476432 :   ulong min_cus   = ULONG_MAX;
    1192     1476432 :   ulong min_bytes = ULONG_MAX;
    1193             : 
    1194     1476432 :   if( FD_UNLIKELY( (cu_limit<smallest_in_treap->cus) | (txn_limit==0UL) | (byte_limit<smallest_in_treap->bytes) ) ) {
    1195      799653 :     sched_return_t to_return = { .cus_scheduled = 0UL, .txns_scheduled = 0UL, .bytes_scheduled = 0UL };
    1196      799653 :     return to_return;
    1197      799653 :   }
    1198             : 
    1199      676779 :   treap_rev_iter_t prev = treap_idx_null();
    1200    32887362 :   for( treap_rev_iter_t _cur=treap_rev_iter_init( sched_from, pool ); !treap_rev_iter_done( _cur ); _cur=prev ) {
    1201             :     /* Capture next so that we can delete while we iterate. */
    1202    32804988 :     prev = treap_rev_iter_next( _cur, pool );
    1203             : 
    1204    32804988 : #   if FD_HAS_X86
    1205    32804988 :     _mm_prefetch( &(pool[ prev ].prev),      _MM_HINT_T0 );
    1206    32804988 : #   endif
    1207             : 
    1208    32804988 :     fd_pack_ord_txn_t const * cur = treap_rev_iter_ele_const( _cur, pool );
    1209             : 
    1210    32804988 :     min_cus   = fd_ulong_min( min_cus,   cur->compute_est     );
    1211    32804988 :     min_bytes = fd_ulong_min( min_bytes, cur->txn->payload_sz );
    1212             : 
    1213    32804988 :     ulong conflicts = 0UL;
    1214             : 
    1215    32804988 :     if( FD_UNLIKELY( cur->compute_est>cu_limit ) ) {
    1216             :       /* Too big to be scheduled at the moment, but might be okay for
    1217             :          the next microblock, so we don't want to delay it. */
    1218           0 :       cu_limit_c++;
    1219           0 :       continue;
    1220           0 :     }
    1221             : 
    1222             :     /* Likely? Unlikely? */
    1223    32804988 :     if( FD_LIKELY( !FD_PACK_BITSET_INTERSECT4_EMPTY( bitset_rw_in_use, bitset_w_in_use, cur->w_bitset, cur->rw_bitset ) ) ) {
    1224    19727613 :       fast_path++;
    1225    19727613 :       continue;
    1226    19727613 :     }
    1227             : 
    1228    13077375 :     if( FD_UNLIKELY( cur->txn->payload_sz>byte_limit ) ) {
    1229           0 :       byte_limit_c++;
    1230           0 :       continue;
    1231           0 :     }
    1232             : 
    1233    13077375 :     fd_txn_t const * txn = TXN(cur->txn);
    1234    13077375 :     fd_acct_addr_t const * accts   = fd_txn_get_acct_addrs( txn, cur->txn->payload );
    1235    13077375 :     fd_acct_addr_t const * alt_adj = cur->txn_e->alt_accts - fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM );
    1236             :     /* Check conflicts between this transaction's writable accounts and
    1237             :        current readers */
    1238    13077375 :     for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
    1239    27316056 :         iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1240             : 
    1241    14238687 :       fd_acct_addr_t acct = *ACCT_ITER_TO_PTR( iter );
    1242             : 
    1243    14238687 :       fd_pack_addr_use_t * in_wcost_table = acct_uses_query( writer_costs, acct, NULL );
    1244    14238687 :       if( FD_UNLIKELY( in_wcost_table && in_wcost_table->total_cost+cur->compute_est > max_write_cost_per_acct ) ) {
    1245             :         /* Can't be scheduled until the next block */
    1246           6 :         conflicts = ULONG_MAX;
    1247           6 :         break;
    1248           6 :       }
    1249             : 
    1250    14238681 :       fd_pack_addr_use_t * use = acct_uses_query( acct_in_use, acct, NULL );
    1251    14238681 :       if( FD_UNLIKELY( use ) ) conflicts |= use->in_use_by; /* break? */
    1252    14238681 :     }
    1253             : 
    1254    13077375 :     if( FD_UNLIKELY( conflicts==ULONG_MAX ) ) {
    1255           6 :       write_limit_c++;
    1256           6 :       continue;
    1257           6 :     }
    1258             : 
    1259    13077369 :     if( FD_UNLIKELY( conflicts ) ) {
    1260           6 :       slow_path++;
    1261           6 :       continue;
    1262           6 :     }
    1263             : 
    1264             :     /* Check conflicts between this transaction's readonly accounts and
    1265             :        current writers */
    1266    13077363 :     for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY );
    1267    16622460 :         iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1268             : 
    1269     3545097 :       fd_acct_addr_t const * acct = ACCT_ITER_TO_PTR( iter );
    1270     3545097 :       if( fd_pack_unwritable_contains( acct ) ) continue; /* No need to track sysvars because they can't be writable */
    1271             : 
    1272     2558586 :       fd_pack_addr_use_t * use = acct_uses_query( acct_in_use,  *acct, NULL );
    1273     2558586 :       if( use ) conflicts |= (use->in_use_by & FD_PACK_IN_USE_WRITABLE) ? use->in_use_by : 0UL;
    1274     2558586 :     }
    1275             : 
    1276    13077363 :     if( FD_UNLIKELY( conflicts ) ) {
    1277           0 :       slow_path++;
    1278           0 :       continue;
    1279           0 :     }
    1280             : 
    1281             :     /* Include this transaction in the microblock! */
    1282    13077363 :     FD_PACK_BITSET_OR( bitset_rw_in_use, cur->rw_bitset );
    1283    13077363 :     FD_PACK_BITSET_OR( bitset_w_in_use,  cur->w_bitset  );
    1284             : 
    1285    13077363 :     if(
    1286     4359121 : #if FD_HAS_AVX512 && FD_PACK_USE_NON_TEMPORAL_MEMCPY
    1287     4359121 :         FD_LIKELY( cur->txn->payload_sz>=1024UL )
    1288             : #else
    1289     8718242 :         0
    1290     8718242 : #endif
    1291    13077363 :       ) {
    1292        4225 : #if FD_HAS_AVX512 && FD_PACK_USE_NON_TEMPORAL_MEMCPY
    1293        4225 :       _mm512_stream_si512( (void*)(out->payload+   0UL), _mm512_load_epi64( cur->txn->payload+   0UL ) );
    1294        4225 :       _mm512_stream_si512( (void*)(out->payload+  64UL), _mm512_load_epi64( cur->txn->payload+  64UL ) );
    1295        4225 :       _mm512_stream_si512( (void*)(out->payload+ 128UL), _mm512_load_epi64( cur->txn->payload+ 128UL ) );
    1296        4225 :       _mm512_stream_si512( (void*)(out->payload+ 192UL), _mm512_load_epi64( cur->txn->payload+ 192UL ) );
    1297        4225 :       _mm512_stream_si512( (void*)(out->payload+ 256UL), _mm512_load_epi64( cur->txn->payload+ 256UL ) );
    1298        4225 :       _mm512_stream_si512( (void*)(out->payload+ 320UL), _mm512_load_epi64( cur->txn->payload+ 320UL ) );
    1299        4225 :       _mm512_stream_si512( (void*)(out->payload+ 384UL), _mm512_load_epi64( cur->txn->payload+ 384UL ) );
    1300        4225 :       _mm512_stream_si512( (void*)(out->payload+ 448UL), _mm512_load_epi64( cur->txn->payload+ 448UL ) );
    1301        4225 :       _mm512_stream_si512( (void*)(out->payload+ 512UL), _mm512_load_epi64( cur->txn->payload+ 512UL ) );
    1302        4225 :       _mm512_stream_si512( (void*)(out->payload+ 576UL), _mm512_load_epi64( cur->txn->payload+ 576UL ) );
    1303        4225 :       _mm512_stream_si512( (void*)(out->payload+ 640UL), _mm512_load_epi64( cur->txn->payload+ 640UL ) );
    1304        4225 :       _mm512_stream_si512( (void*)(out->payload+ 704UL), _mm512_load_epi64( cur->txn->payload+ 704UL ) );
    1305        4225 :       _mm512_stream_si512( (void*)(out->payload+ 768UL), _mm512_load_epi64( cur->txn->payload+ 768UL ) );
    1306        4225 :       _mm512_stream_si512( (void*)(out->payload+ 832UL), _mm512_load_epi64( cur->txn->payload+ 832UL ) );
    1307        4225 :       _mm512_stream_si512( (void*)(out->payload+ 896UL), _mm512_load_epi64( cur->txn->payload+ 896UL ) );
    1308        4225 :       _mm512_stream_si512( (void*)(out->payload+ 960UL), _mm512_load_epi64( cur->txn->payload+ 960UL ) );
    1309        4225 :       _mm512_stream_si512( (void*)(out->payload+1024UL), _mm512_load_epi64( cur->txn->payload+1024UL ) );
    1310        4225 :       _mm512_stream_si512( (void*)(out->payload+1088UL), _mm512_load_epi64( cur->txn->payload+1088UL ) );
    1311        4225 :       _mm512_stream_si512( (void*)(out->payload+1152UL), _mm512_load_epi64( cur->txn->payload+1152UL ) );
    1312        4225 :       _mm512_stream_si512( (void*)(out->payload+1216UL), _mm512_load_epi64( cur->txn->payload+1216UL ) );
    1313             :       /* Copied out to 1280 bytes, which copies some other fields we needed to
    1314             :          copy anyway. */
    1315        4225 :       FD_STATIC_ASSERT( offsetof(fd_txn_p_t, payload_sz     )+sizeof(((fd_txn_p_t*)NULL)->payload_sz    )<=1280UL, nt_memcpy );
    1316        4225 :       FD_STATIC_ASSERT( offsetof(fd_txn_p_t, blockhash_slot )+sizeof(((fd_txn_p_t*)NULL)->blockhash_slot)<=1280UL, nt_memcpy );
    1317        4225 :       FD_STATIC_ASSERT( offsetof(fd_txn_p_t, flags          )+sizeof(((fd_txn_p_t*)NULL)->flags         )<=1280UL, nt_memcpy );
    1318        4225 :       FD_STATIC_ASSERT( offsetof(fd_txn_p_t, _              )                                            <=1280UL, nt_memcpy );
    1319        4225 :       const ulong offset_into_txn = 1280UL - offsetof(fd_txn_p_t, _ );
    1320        4225 :       fd_memcpy( offset_into_txn+(uchar *)TXN(out), offset_into_txn+(uchar const *)txn,
    1321        4225 :           fd_ulong_max( offset_into_txn, fd_txn_footprint( txn->instr_cnt, txn->addr_table_lookup_cnt ) )-offset_into_txn );
    1322        4225 : #endif
    1323    13073138 :     } else {
    1324    13073138 :       fd_memcpy( out->payload, cur->txn->payload, cur->txn->payload_sz                                           );
    1325    13073138 :       fd_memcpy( TXN(out),     txn,               fd_txn_footprint( txn->instr_cnt, txn->addr_table_lookup_cnt ) );
    1326    13073138 :       out->payload_sz                      = cur->txn->payload_sz;
    1327    13073138 :       out->pack_cu.requested_execution_cus = cur->txn->pack_cu.requested_execution_cus;
    1328    13073138 :       out->pack_cu.non_execution_cus       = cur->txn->pack_cu.non_execution_cus;
    1329    13073138 :       out->flags                           = cur->txn->flags;
    1330    13073138 :     }
    1331    13077363 :     out++;
    1332             : 
    1333    13077363 :     for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
    1334    27316032 :         iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1335    14238669 :       fd_acct_addr_t acct_addr = *ACCT_ITER_TO_PTR( iter );
    1336             : 
    1337    14238669 :       fd_pack_addr_use_t * in_wcost_table = acct_uses_query( writer_costs, acct_addr, NULL );
    1338    14238669 :       if( !in_wcost_table ) {
    1339      788031 :         in_wcost_table = acct_uses_insert( writer_costs, acct_addr );
    1340      788031 :         in_wcost_table->total_cost = 0UL;
    1341      788031 :         written_list[ written_list_cnt ] = in_wcost_table;
    1342      788031 :         written_list_cnt = fd_ulong_min( written_list_cnt+1UL, written_list_max-1UL );
    1343      788031 :       }
    1344    14238669 :       in_wcost_table->total_cost += cur->compute_est;
    1345             : 
    1346    14238669 :       fd_pack_addr_use_t * use = acct_uses_insert( acct_in_use, acct_addr );
    1347    14238669 :       use->in_use_by = bank_tile_mask | FD_PACK_IN_USE_WRITABLE;
    1348             : 
    1349    14238669 :       use_by_bank[use_by_bank_cnt++] = *use;
    1350             : 
    1351             :       /* If there aren't any more references to this account in the
    1352             :          heap, it can't cause any conflicts.  That means we actually
    1353             :          don't need to record that we are using it, which is good
    1354             :          because we want to release the bit. */
    1355    14238669 :       release_result_t ret = release_bit_reference( pack, &acct_addr );
    1356    14238669 :       FD_PACK_BITSET_CLEARN( bitset_rw_in_use, ret.clear_rw_bit );
    1357    14238669 :       FD_PACK_BITSET_CLEARN( bitset_w_in_use,  ret.clear_w_bit  );
    1358    14238669 :     }
    1359    13077363 :     for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY );
    1360    16622460 :         iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1361             : 
    1362     3545097 :       fd_acct_addr_t acct_addr = *ACCT_ITER_TO_PTR( iter );
    1363             : 
    1364     3545097 :       if( fd_pack_unwritable_contains( &acct_addr ) ) continue; /* No need to track sysvars because they can't be writable */
    1365             : 
    1366     2558586 :       fd_pack_addr_use_t * use = acct_uses_query( acct_in_use,  acct_addr, NULL );
    1367     2558586 :       if( !use ) { use = acct_uses_insert( acct_in_use, acct_addr ); use->in_use_by = 0UL; }
    1368             : 
    1369     2558586 :       if( !(use->in_use_by & bank_tile_mask) ) use_by_bank[use_by_bank_cnt++] = *use;
    1370     2558586 :       use->in_use_by |= bank_tile_mask;
    1371     2558586 :       use->in_use_by &= ~FD_PACK_IN_USE_BIT_CLEARED;
    1372             : 
    1373             : 
    1374     2558586 :       release_result_t ret = release_bit_reference( pack, &acct_addr );
    1375     2558586 :       FD_PACK_BITSET_CLEARN( bitset_rw_in_use, ret.clear_rw_bit );
    1376     2558586 :       FD_PACK_BITSET_CLEARN( bitset_w_in_use,  ret.clear_w_bit  );
    1377     2558586 :     }
    1378             : 
    1379    13077363 :     txns_scheduled  += 1UL;                      txn_limit       -= 1UL;
    1380    13077363 :     cus_scheduled   += cur->compute_est;         cu_limit        -= cur->compute_est;
    1381    13077363 :     bytes_scheduled += cur->txn->payload_sz;     byte_limit      -= cur->txn->payload_sz;
    1382             : 
    1383    13077363 :     *(use_by_bank_txn++) = use_by_bank_cnt;
    1384             : 
    1385    13077363 :     fd_ed25519_sig_t const * sig0 = fd_txn_get_signatures( txn, cur->txn->payload );
    1386             : 
    1387    13077363 :     fd_pack_sig_to_txn_t * in_tbl = sig2txn_query( pack->signature_map, sig0, NULL );
    1388    13077363 :     sig2txn_remove( pack->signature_map, in_tbl );
    1389             : 
    1390    13077363 :     expq_remove( pack->expiration_q, cur->expq_idx );
    1391    13077363 :     treap_idx_remove( sched_from, _cur, pool );
    1392    13077363 :     trp_pool_idx_release( pool, _cur );
    1393    13077363 :     pack->pending_txn_cnt--;
    1394             : 
    1395    13077363 :     if( FD_UNLIKELY( (cu_limit<smallest_in_treap->cus) | (txn_limit==0UL) | (byte_limit<smallest_in_treap->bytes) ) ) break;
    1396    13077363 :   }
    1397             : 
    1398      676779 :   FD_MCNT_INC( PACK, TRANSACTION_SCHEDULE_TAKEN,      txns_scheduled );
    1399      676779 :   FD_MCNT_INC( PACK, TRANSACTION_SCHEDULE_CU_LIMIT,   cu_limit_c     );
    1400      676779 :   FD_MCNT_INC( PACK, TRANSACTION_SCHEDULE_FAST_PATH,  fast_path      );
    1401      676779 :   FD_MCNT_INC( PACK, TRANSACTION_SCHEDULE_BYTE_LIMIT, byte_limit_c   );
    1402      676779 :   FD_MCNT_INC( PACK, TRANSACTION_SCHEDULE_WRITE_COST, write_limit_c  );
    1403      676779 :   FD_MCNT_INC( PACK, TRANSACTION_SCHEDULE_SLOW_PATH,  slow_path      );
    1404             : 
    1405             : #if DETAILED_LOGGING
    1406             :   FD_LOG_NOTICE(( "cu_limit: %lu, fast_path: %lu, slow_path: %lu", cu_limit_c, fast_path, slow_path ));
    1407             : #endif
    1408             : 
    1409             :   /* If we scanned the whole treap and didn't break early, we now have a
    1410             :      better estimate of the smallest. */
    1411      676779 :   if( FD_UNLIKELY( treap_rev_iter_done( prev ) ) ) {
    1412       85419 :     smallest_in_treap->cus   = min_cus;
    1413       85419 :     smallest_in_treap->bytes = min_bytes;
    1414       85419 :   }
    1415             : 
    1416      676779 :   pack->use_by_bank_cnt[bank_tile] = use_by_bank_cnt;
    1417      676779 :   FD_PACK_BITSET_COPY( pack->bitset_rw_in_use, bitset_rw_in_use );
    1418      676779 :   FD_PACK_BITSET_COPY( pack->bitset_w_in_use,  bitset_w_in_use  );
    1419             : 
    1420      676779 :   pack->written_list_cnt = written_list_cnt;
    1421             : 
    1422      676779 :   sched_return_t to_return = { .cus_scheduled=cus_scheduled, .txns_scheduled=txns_scheduled, .bytes_scheduled=bytes_scheduled };
    1423      676779 :   return to_return;
    1424     1476432 : }
    1425             : 
    1426             : int
    1427             : fd_pack_microblock_complete( fd_pack_t * pack,
    1428      738216 :                              ulong       bank_tile ) {
    1429             :   /* If the account is in use writably, and it's in use by this banking
    1430             :      tile, then this banking tile must be the sole writer to it, so it's
    1431             :      always okay to clear the writable bit. */
    1432      738216 :   ulong clear_mask = ~((1UL<<bank_tile) | FD_PACK_IN_USE_WRITABLE);
    1433             : 
    1434             :   /* If nothing outstanding, bail quickly */
    1435      738216 :   if( FD_UNLIKELY( !(pack->outstanding_microblock_mask & (1UL<<bank_tile)) ) ) return 0;
    1436             : 
    1437      670812 :   FD_PACK_BITSET_DECLARE( bitset_rw_in_use );
    1438      670812 :   FD_PACK_BITSET_DECLARE( bitset_w_in_use  );
    1439      670812 :   FD_PACK_BITSET_COPY( bitset_rw_in_use, pack->bitset_rw_in_use );
    1440      670812 :   FD_PACK_BITSET_COPY( bitset_w_in_use,  pack->bitset_w_in_use  );
    1441             : 
    1442      670812 :   fd_pack_addr_use_t * base = pack->use_by_bank[bank_tile];
    1443             : 
    1444      670812 :   fd_pack_ord_txn_t       * best         = NULL;
    1445      670812 :   fd_pack_penalty_treap_t * best_penalty = NULL;
    1446      670812 :   ulong                     txn_cnt      = 0UL;
    1447             : 
    1448    16851819 :   for( ulong i=0UL; i<pack->use_by_bank_cnt[bank_tile]; i++ ) {
    1449    16181007 :     fd_pack_addr_use_t * use = acct_uses_query( pack->acct_in_use, base[i].key, NULL );
    1450    16181007 :     FD_TEST( use );
    1451    16181007 :     use->in_use_by &= clear_mask;
    1452             : 
    1453             :     /* In order to properly bound the size of bitset_map, we need to
    1454             :        release the "reference" to the account when we schedule it.
    1455             :        However, that poses a bit of a problem here, because by the time
    1456             :        we complete the microblock, that account could have been assigned
    1457             :        a different bit in the bitset.  The scheduling step tells us if
    1458             :        that is the case, and if so, we know that the bits in
    1459             :        bitset_w_in_use and bitset_rw_in_use were already cleared as
    1460             :        necessary.
    1461             : 
    1462             :        Note that it's possible for BIT_CLEARED to be set and then unset
    1463             :        by later uses, but then the account would be in use on other
    1464             :        banks, so we wouldn't try to observe the old value.  For example:
    1465             :        Suppose bit 0->account A, bit 1->account B, and we have two
    1466             :        transactions that read A, B.  We schedule a microblock to bank 0,
    1467             :        taking both transactions, which sets the counts for A, B to 0,
    1468             :        and releases the bits, clearing bits 0 and 1, and setting
    1469             :        BIT_CLEARED.  Then we get two more transactions that read
    1470             :        accounts C, D, A, B, and they get assigned 0->C, 1->D, 2->A,
    1471             :        3->B.  We try to schedule a microblock to bank 1 that takes one
    1472             :        of those transactions.   This unsets BIT_CLEARED for A, B.
    1473             :        Finally, the first microblock completes.  Even though the bitset
    1474             :        map has the new bits for A and B which are "wrong" compared to
    1475             :        when the transaction was initially scheduled, those bits have
    1476             :        already been cleared and reset properly in the bitset as needed.
    1477             :        A and B will still be in use by bank 1, so we won't clear any
    1478             :        bits.  If, on the other hand, the microblock scheduled to bank 1
    1479             :        completes first, bits 0 and 1 will be cleared for accounts C and
    1480             :        D, while bits 2 and 3 will remain set, which is correct.  Then
    1481             :        when bank 0 completes, bits 2 and 3 will be cleared. */
    1482    16181007 :     if( FD_LIKELY( !use->in_use_by ) ) { /* if in_use_by==0, doesn't include BIT_CLEARED */
    1483     3401988 :       fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, base[i].key, NULL );
    1484     3401988 :       FD_TEST( q );
    1485     3401988 :       FD_PACK_BITSET_CLEARN( bitset_w_in_use,  q->bit );
    1486     3401988 :       FD_PACK_BITSET_CLEARN( bitset_rw_in_use, q->bit );
    1487             : 
    1488             :       /* Because this account is no longer in use, it might be possible
    1489             :          to schedule a transaction that writes to it.  Check it's
    1490             :          penalty treap if it has one, and potentially move it to the
    1491             :          main treap. */
    1492     3401988 :       fd_pack_penalty_treap_t * p_trp = penalty_map_query( pack->penalty_treaps, base[i].key, NULL );
    1493     3401988 :       if( FD_UNLIKELY( p_trp ) ) {
    1494      639208 :         fd_pack_ord_txn_t * best_in_trp = treap_rev_iter_ele( treap_rev_iter_init( p_trp->penalty_treap, pack->pool ), pack->pool );
    1495      639208 :         if( FD_UNLIKELY( !best || COMPARE_WORSE( best, best_in_trp ) ) ) {
    1496      255569 :           best         = best_in_trp;
    1497      255569 :           best_penalty = p_trp;
    1498      255569 :         }
    1499      639208 :       }
    1500     3401988 :     }
    1501             : 
    1502    16181007 :     if( FD_LIKELY( !(use->in_use_by & ~FD_PACK_IN_USE_BIT_CLEARED) ) ) acct_uses_remove( pack->acct_in_use, use );
    1503             : 
    1504    16181007 :     if( FD_UNLIKELY( i+1UL==pack->use_by_bank_txn[ bank_tile ][ txn_cnt ] ) ) {
    1505    13073553 :       txn_cnt++;
    1506    13073553 :       if( FD_LIKELY( best ) ) {
    1507             :         /* move best to the main treap */
    1508      255569 :         treap_ele_remove( best_penalty->penalty_treap, best, pack->pool );
    1509      255569 :         best->root = FD_ORD_TXN_ROOT_PENDING;
    1510      255569 :         treap_ele_insert( pack->pending,               best, pack->pool );
    1511             : 
    1512      255569 :         pack->pending_smallest->cus   = fd_ulong_min( pack->pending_smallest->cus,   best->compute_est             );
    1513      255569 :         pack->pending_smallest->bytes = fd_ulong_min( pack->pending_smallest->bytes, best->txn_e->txnp->payload_sz );
    1514             : 
    1515      255569 :         if( FD_UNLIKELY( !treap_ele_cnt( best_penalty->penalty_treap ) ) ) {
    1516        2181 :           treap_delete( treap_leave( best_penalty->penalty_treap ) );
    1517             :           /* Removal invalidates any pointers we got from
    1518             :              penalty_map_query, but we immediately set these to NULL, so
    1519             :              we're not keeping any pointers around. */
    1520        2181 :           penalty_map_remove( pack->penalty_treaps, best_penalty );
    1521        2181 :         }
    1522      255569 :         best         = NULL;
    1523      255569 :         best_penalty = NULL;
    1524      255569 :       }
    1525    13073553 :     }
    1526    16181007 :   }
    1527             : 
    1528      670812 :   pack->use_by_bank_cnt[bank_tile] = 0UL;
    1529             : 
    1530      670812 :   FD_PACK_BITSET_COPY( pack->bitset_rw_in_use, bitset_rw_in_use );
    1531      670812 :   FD_PACK_BITSET_COPY( pack->bitset_w_in_use,  bitset_w_in_use  );
    1532             : 
    1533             :   /* outstanding_microblock_mask never has the writable bit set, so we
    1534             :      don't care about clearing it here either. */
    1535      670812 :   pack->outstanding_microblock_mask &= clear_mask;
    1536      670812 :   return 1;
    1537      670812 : }
    1538             : 
    1539             : 
    1540             : ulong
    1541             : fd_pack_schedule_next_microblock( fd_pack_t *  pack,
    1542             :                                   ulong        total_cus,
    1543             :                                   float        vote_fraction,
    1544             :                                   ulong        bank_tile,
    1545      738216 :                                   fd_txn_p_t * out ) {
    1546             : 
    1547             :   /* TODO: Decide if these are exactly how we want to handle limits */
    1548      738216 :   total_cus = fd_ulong_min( total_cus, pack->lim->max_cost_per_block - pack->cumulative_block_cost );
    1549      738216 :   ulong vote_cus = fd_ulong_min( (ulong)((float)total_cus * vote_fraction),
    1550      738216 :                                  pack->lim->max_vote_cost_per_block - pack->cumulative_vote_cost );
    1551      738216 :   ulong vote_reserved_txns = fd_ulong_min( vote_cus/FD_PACK_TYPICAL_VOTE_COST,
    1552      738216 :                                            (ulong)((float)pack->lim->max_txn_per_microblock * vote_fraction) );
    1553             : 
    1554             : 
    1555      738216 :   if( FD_UNLIKELY( (pack->microblock_cnt>=pack->lim->max_microblocks_per_block) ) ) {
    1556           0 :     FD_MCNT_INC( PACK, MICROBLOCK_PER_BLOCK_LIMIT, 1UL );
    1557           0 :     return 0UL;
    1558           0 :   }
    1559      738216 :   if( FD_UNLIKELY( pack->data_bytes_consumed+MICROBLOCK_DATA_OVERHEAD+FD_TXN_MIN_SERIALIZED_SZ>pack->lim->max_data_bytes_per_block) ) {
    1560           0 :     FD_MCNT_INC( PACK, DATA_PER_BLOCK_LIMIT, 1UL );
    1561           0 :     return 0UL;
    1562           0 :   }
    1563             : 
    1564      738216 :   ulong * use_by_bank_txn = pack->use_by_bank_txn[ bank_tile ];
    1565             : 
    1566      738216 :   ulong cu_limit  = total_cus - vote_cus;
    1567      738216 :   ulong txn_limit = pack->lim->max_txn_per_microblock - vote_reserved_txns;
    1568      738216 :   ulong scheduled = 0UL;
    1569      738216 :   ulong byte_limit = pack->lim->max_data_bytes_per_block - pack->data_bytes_consumed - MICROBLOCK_DATA_OVERHEAD;
    1570             : 
    1571      738216 :   sched_return_t status, status1;
    1572             : 
    1573             :   /* Schedule vote transactions */
    1574      738216 :   status1= fd_pack_schedule_impl( pack, pack->pending_votes, vote_cus, vote_reserved_txns, byte_limit, bank_tile, pack->pending_votes_smallest, use_by_bank_txn, out+scheduled );
    1575             : 
    1576      738216 :   scheduled                   += status1.txns_scheduled;
    1577      738216 :   pack->cumulative_vote_cost  += status1.cus_scheduled;
    1578      738216 :   pack->cumulative_block_cost += status1.cus_scheduled;
    1579      738216 :   pack->data_bytes_consumed   += status1.bytes_scheduled;
    1580      738216 :   byte_limit                  -= status1.bytes_scheduled;
    1581      738216 :   use_by_bank_txn             += status1.txns_scheduled;
    1582             :   /* Add any remaining CUs/txns to the non-vote limits */
    1583      738216 :   txn_limit += vote_reserved_txns - status1.txns_scheduled;
    1584      738216 :   cu_limit  += vote_cus - status1.cus_scheduled;
    1585             : 
    1586             : 
    1587             :   /* Fill any remaining space with non-vote transactions */
    1588      738216 :   status = fd_pack_schedule_impl( pack, pack->pending,       cu_limit, txn_limit,          byte_limit, bank_tile, pack->pending_smallest,       use_by_bank_txn, out+scheduled );
    1589             : 
    1590      738216 :   scheduled                   += status.txns_scheduled;
    1591      738216 :   pack->cumulative_block_cost += status.cus_scheduled;
    1592      738216 :   pack->data_bytes_consumed   += status.bytes_scheduled;
    1593             : 
    1594      738216 :   ulong nonempty = (ulong)(scheduled>0UL);
    1595      738216 :   pack->microblock_cnt              += nonempty;
    1596      738216 :   pack->outstanding_microblock_mask |= nonempty << bank_tile;
    1597      738216 :   pack->data_bytes_consumed         += nonempty * MICROBLOCK_DATA_OVERHEAD;
    1598             : 
    1599             :   /* Update metrics counters */
    1600      738216 :   FD_MGAUGE_SET( PACK, AVAILABLE_TRANSACTIONS,      pack->pending_txn_cnt                );
    1601      738216 :   FD_MGAUGE_SET( PACK, AVAILABLE_VOTE_TRANSACTIONS, treap_ele_cnt( pack->pending_votes ) );
    1602      738216 :   FD_MGAUGE_SET( PACK, CUS_CONSUMED_IN_BLOCK,       pack->cumulative_block_cost          );
    1603             : 
    1604      738216 :   fd_histf_sample( pack->txn_per_microblock,  scheduled              );
    1605      738216 :   fd_histf_sample( pack->vote_per_microblock, status1.txns_scheduled );
    1606             : 
    1607      246072 : #if FD_HAS_AVX512 && FD_PACK_USE_NON_TEMPORAL_MEMCPY
    1608      246072 :   _mm_sfence();
    1609      246072 : #endif
    1610             : 
    1611      738216 :   return scheduled;
    1612      738216 : }
    1613             : 
    1614      268194 : ulong fd_pack_bank_tile_cnt     ( fd_pack_t const * pack ) { return pack->bank_tile_cnt;         }
    1615           0 : ulong fd_pack_current_block_cost( fd_pack_t const * pack ) { return pack->cumulative_block_cost; }
    1616             : 
    1617             : 
    1618             : void
    1619             : fd_pack_set_block_limits( fd_pack_t * pack,
    1620             :                           ulong       max_microblocks_per_block,
    1621           0 :                           ulong       max_data_bytes_per_block ) {
    1622           0 :   pack->lim->max_microblocks_per_block = max_microblocks_per_block;
    1623           0 :   pack->lim->max_data_bytes_per_block  = max_data_bytes_per_block;
    1624           0 : }
    1625             : 
    1626             : void
    1627             : fd_pack_rebate_cus( fd_pack_t        * pack,
    1628             :                     fd_txn_p_t const * txns,
    1629           6 :                     ulong              txn_cnt ) {
    1630           6 :   fd_pack_addr_use_t * writer_costs = pack->writer_costs;
    1631             : 
    1632           6 :   ulong cumulative_vote_cost   = pack->cumulative_vote_cost;
    1633           6 :   ulong cumulative_block_cost  = pack->cumulative_block_cost;
    1634           6 :   ulong data_bytes_consumed    = pack->data_bytes_consumed;
    1635           6 :   ulong cumulative_rebated_cus = pack->cumulative_rebated_cus;
    1636             : 
    1637          18 :   for( ulong i=0UL; i<txn_cnt; i++ ) {
    1638          12 :     fd_txn_p_t const * txn = txns+i;
    1639          12 :     ulong rebated_cus   = txn->bank_cu.rebated_cus;
    1640          12 :     int   in_block      = !!(txn->flags & FD_TXN_P_FLAGS_EXECUTE_SUCCESS);
    1641             : 
    1642          12 :     cumulative_block_cost  -= rebated_cus;
    1643          12 :     cumulative_vote_cost   -= fd_ulong_if( txn->flags & FD_TXN_P_FLAGS_IS_SIMPLE_VOTE, rebated_cus,     0UL );
    1644          12 :     data_bytes_consumed    -= fd_ulong_if( !in_block,                                  txn->payload_sz, 0UL );
    1645          12 :     cumulative_rebated_cus += rebated_cus;
    1646             : 
    1647          12 :     fd_acct_addr_t const * accts = fd_txn_get_acct_addrs( TXN(txn), txn->payload );
    1648             :     /* TODO: For now, we don't have a way to rebate writer costs for ALT
    1649             :        accounts.  We've thrown away the ALT expansion at this point.
    1650             :        The rebate system is going to be rewritten soon for performance,
    1651             :        so it's okay. */
    1652          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 );
    1653          36 :         iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1654             : 
    1655          24 :       ulong i=fd_txn_acct_iter_idx( iter );
    1656             : 
    1657          24 :       fd_pack_addr_use_t * in_wcost_table = acct_uses_query( writer_costs, accts[i], NULL );
    1658          24 :       if( FD_UNLIKELY( !in_wcost_table ) ) FD_LOG_ERR(( "Rebate to unknown written account" ));
    1659          24 :       in_wcost_table->total_cost -= rebated_cus;
    1660             :       /* Important: Even if this is 0, don't delete it from the table so
    1661             :          that the insert order doesn't get messed up. */
    1662          24 :     }
    1663          12 :   }
    1664             : 
    1665           6 :   pack->cumulative_vote_cost   = cumulative_vote_cost;
    1666           6 :   pack->cumulative_block_cost  = cumulative_block_cost;
    1667           6 :   pack->data_bytes_consumed    = data_bytes_consumed;
    1668           6 :   pack->cumulative_rebated_cus = cumulative_rebated_cus;
    1669           6 : }
    1670             : 
    1671             : 
    1672             : ulong
    1673             : fd_pack_expire_before( fd_pack_t * pack,
    1674           9 :                        ulong       expire_before ) {
    1675           9 :   expire_before = fd_ulong_max( expire_before, pack->expire_before );
    1676           9 :   ulong deleted_cnt = 0UL;
    1677           9 :   fd_pack_expq_t * prq = pack->expiration_q;
    1678          18 :   while( (expq_cnt( prq )>0UL) & (prq->expires_at<expire_before) ) {
    1679           9 :     fd_pack_ord_txn_t * expired = prq->txn;
    1680             : 
    1681           9 :     fd_ed25519_sig_t const * expired_sig = fd_txn_get_signatures( TXN( expired->txn ), expired->txn->payload );
    1682             :     /* fd_pack_delete_transaction also removes it from the heap */
    1683           9 :     fd_pack_delete_transaction( pack, expired_sig );
    1684           9 :     deleted_cnt++;
    1685           9 :   }
    1686             : 
    1687           9 :   pack->expire_before = expire_before;
    1688           9 :   return deleted_cnt;
    1689           9 : }
    1690             : 
    1691             : void
    1692        2646 : fd_pack_end_block( fd_pack_t * pack ) {
    1693        2646 :   fd_histf_sample( pack->net_cus_per_block,       pack->cumulative_block_cost                                );
    1694        2646 :   fd_histf_sample( pack->rebated_cus_per_block,   pack->cumulative_rebated_cus                               );
    1695        2646 :   fd_histf_sample( pack->scheduled_cus_per_block, pack->cumulative_rebated_cus + pack->cumulative_block_cost );
    1696             : 
    1697        2646 :   pack->microblock_cnt         = 0UL;
    1698        2646 :   pack->data_bytes_consumed    = 0UL;
    1699        2646 :   pack->cumulative_block_cost  = 0UL;
    1700        2646 :   pack->cumulative_vote_cost   = 0UL;
    1701        2646 :   pack->cumulative_rebated_cus = 0UL;
    1702             : 
    1703        2646 :   acct_uses_clear( pack->acct_in_use  );
    1704             : 
    1705        2646 :   if( FD_LIKELY( pack->written_list_cnt<pack->written_list_max-1UL ) ) {
    1706             :     /* The less dangerous way of doing this is to instead record the
    1707             :        keys we inserted and do a query followed by a delete for each
    1708             :        key.  The downside of that is that keys are 32 bytes and a
    1709             :        pointer is only 8 bytes, plus the computational cost for the
    1710             :        query.
    1711             : 
    1712             :        However, if we're careful, we can pull this off.  We require two
    1713             :        things.  First, we started from an empty map and did nothing but
    1714             :        insert and update.  In particular, no deletions.  Second, we have
    1715             :        to be careful to delete in the opposite order that we inserted.
    1716             :        This is essentially like unwinding the inserts we did.  The
    1717             :        common case is that the element after the one we delete will be
    1718             :        empty, so we'll hit that case.  It's possible that there's
    1719             :        another independent probe sequence that will be entirely intact
    1720             :        starting in the element after, but we'll never hit the MAP_MOVE
    1721             :        case. */
    1722      776193 :     for( ulong i=0UL; i<pack->written_list_cnt; i++ ) {
    1723      773547 :       acct_uses_remove( pack->writer_costs, pack->written_list[ pack->written_list_cnt - 1UL - i ] );
    1724      773547 :     }
    1725        2646 :   } else {
    1726           0 :     acct_uses_clear( pack->writer_costs );
    1727           0 :   }
    1728        2646 :   pack->written_list_cnt = 0UL;
    1729             : 
    1730        2646 :   FD_PACK_BITSET_CLEAR( pack->bitset_rw_in_use );
    1731        2646 :   FD_PACK_BITSET_CLEAR( pack->bitset_w_in_use  );
    1732             : 
    1733        9234 :   for( ulong i=0UL; i<pack->bank_tile_cnt; i++ ) pack->use_by_bank_cnt[i] = 0UL;
    1734             : 
    1735             :   /* If our stake is low and we don't become leader often, end_block
    1736             :      might get called on the order of O(1/hr), which feels too
    1737             :      infrequent to do anything related to metrics.  However, we only
    1738             :      update the histograms when we are leader, so this is actually a
    1739             :      good place to copy them. */
    1740        2646 :   FD_MHIST_COPY( PACK, TOTAL_TRANSACTIONS_PER_MICROBLOCK_COUNT, pack->txn_per_microblock  );
    1741        2646 :   FD_MHIST_COPY( PACK, VOTES_PER_MICROBLOCK_COUNT,              pack->vote_per_microblock );
    1742             : 
    1743        2646 :   FD_MGAUGE_SET( PACK, CUS_CONSUMED_IN_BLOCK, 0UL                           );
    1744        2646 :   FD_MHIST_COPY( PACK, CUS_SCHEDULED,         pack->scheduled_cus_per_block );
    1745        2646 :   FD_MHIST_COPY( PACK, CUS_REBATED,           pack->rebated_cus_per_block   );
    1746        2646 :   FD_MHIST_COPY( PACK, CUS_NET,               pack->net_cus_per_block       );
    1747        2646 : }
    1748             : 
    1749             : static void
    1750             : release_tree( treap_t           * treap,
    1751           0 :               fd_pack_ord_txn_t * pool ) {
    1752           0 :   treap_fwd_iter_t next;
    1753           0 :   for( treap_fwd_iter_t it=treap_fwd_iter_init( treap, pool ); !treap_fwd_iter_idx( it ); it=next ) {
    1754           0 :     next = treap_fwd_iter_next( it, pool );
    1755           0 :     ulong idx = treap_fwd_iter_idx( it );
    1756           0 :     pool[ idx ].root = FD_ORD_TXN_ROOT_FREE;
    1757           0 :     treap_idx_remove    ( treap, idx, pool );
    1758           0 :     trp_pool_idx_release( pool,  idx       );
    1759           0 :   }
    1760           0 : }
    1761             : 
    1762             : void
    1763           0 : fd_pack_clear_all( fd_pack_t * pack ) {
    1764           0 :   pack->pending_txn_cnt        = 0UL;
    1765           0 :   pack->microblock_cnt         = 0UL;
    1766           0 :   pack->cumulative_block_cost  = 0UL;
    1767           0 :   pack->cumulative_vote_cost   = 0UL;
    1768           0 :   pack->cumulative_rebated_cus = 0UL;
    1769             : 
    1770           0 :   pack->pending_smallest->cus         = ULONG_MAX;
    1771           0 :   pack->pending_smallest->bytes       = ULONG_MAX;
    1772           0 :   pack->pending_votes_smallest->cus   = ULONG_MAX;
    1773           0 :   pack->pending_votes_smallest->bytes = ULONG_MAX;
    1774             : 
    1775           0 :   release_tree( pack->pending,         pack->pool );
    1776           0 :   release_tree( pack->pending_votes,   pack->pool );
    1777           0 :   for( ulong i=0UL; i<pack->pack_depth+1UL; i++ ) {
    1778           0 :     if( FD_UNLIKELY( pack->pool[ i ].root!=FD_ORD_TXN_ROOT_FREE ) ) {
    1779           0 :       fd_pack_ord_txn_t * const del = pack->pool + i;
    1780           0 :       fd_txn_t * txn = TXN( del->txn );
    1781           0 :       fd_acct_addr_t const * accts   = fd_txn_get_acct_addrs( txn, del->txn->payload );
    1782           0 :       fd_acct_addr_t const * alt_adj = del->txn_e->alt_accts - fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM );
    1783           0 :       fd_acct_addr_t penalty_acct = *ACCT_IDX_TO_PTR( FD_ORD_TXN_ROOT_PENALTY_ACCT_IDX( del->root ) );
    1784           0 :       fd_pack_penalty_treap_t * penalty_treap = penalty_map_query( pack->penalty_treaps, penalty_acct, NULL );
    1785           0 :       FD_TEST( penalty_treap );
    1786           0 :       release_tree( penalty_treap->penalty_treap, pack->pool );
    1787           0 :     }
    1788           0 :   }
    1789             : 
    1790           0 :   expq_remove_all( pack->expiration_q );
    1791             : 
    1792           0 :   acct_uses_clear( pack->acct_in_use  );
    1793           0 :   acct_uses_clear( pack->writer_costs );
    1794             : 
    1795           0 :   sig2txn_clear( pack->signature_map );
    1796             : 
    1797           0 :   penalty_map_clear( pack->penalty_treaps );
    1798             : 
    1799           0 :   FD_PACK_BITSET_CLEAR( pack->bitset_rw_in_use );
    1800           0 :   FD_PACK_BITSET_CLEAR( pack->bitset_w_in_use  );
    1801           0 :   bitset_map_clear( pack->acct_to_bitset );
    1802           0 :   pack->bitset_avail[ 0 ] = FD_PACK_BITSET_SLOWPATH;
    1803           0 :   for( ulong i=0UL; i<FD_PACK_BITSET_MAX; i++ ) pack->bitset_avail[ i+1UL ] = (ushort)i;
    1804           0 :   pack->bitset_avail_cnt = FD_PACK_BITSET_MAX;
    1805             : 
    1806           0 :   for( ulong i=0UL; i<pack->bank_tile_cnt; i++ ) pack->use_by_bank_cnt[i] = 0UL;
    1807           0 : }
    1808             : 
    1809             : int
    1810             : fd_pack_delete_transaction( fd_pack_t              * pack,
    1811      494646 :                             fd_ed25519_sig_t const * sig0 ) {
    1812      494646 :   fd_pack_sig_to_txn_t * in_tbl = sig2txn_query( pack->signature_map, sig0, NULL );
    1813             : 
    1814      494646 :   if( !in_tbl )
    1815          24 :     return 0;
    1816             : 
    1817             :   /* The static asserts enforce that the payload of the transaction is
    1818             :      the first element of the fd_pack_ord_txn_t struct.  The signature
    1819             :      we insert is 1 byte into the start of the payload. */
    1820      494622 :   fd_pack_ord_txn_t * containing = (fd_pack_ord_txn_t *)( (uchar*)in_tbl->key - 1UL );
    1821             : 
    1822      494622 :   fd_txn_t * txn = TXN( containing->txn );
    1823      494622 :   fd_acct_addr_t const * accts   = fd_txn_get_acct_addrs( txn, containing->txn->payload );
    1824      494622 :   fd_acct_addr_t const * alt_adj = containing->txn_e->alt_accts - fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM );
    1825             : 
    1826      494622 :   treap_t * root = NULL;
    1827      494622 :   int root_idx = containing->root;
    1828      494622 :   fd_pack_penalty_treap_t * penalty_treap = NULL;
    1829      494622 :   switch( root_idx & FD_ORD_TXN_ROOT_TAG_MASK ) {
    1830           0 :     case FD_ORD_TXN_ROOT_FREE:             /* Should be impossible */                                                return 0;
    1831      491918 :     case FD_ORD_TXN_ROOT_PENDING:          root = pack->pending;                                                     break;
    1832           0 :     case FD_ORD_TXN_ROOT_PENDING_VOTE:     root = pack->pending_votes;                                               break;
    1833        2704 :     case FD_ORD_TXN_ROOT_PENALTY( 0 ): {
    1834        2704 :       fd_acct_addr_t penalty_acct = *ACCT_IDX_TO_PTR( FD_ORD_TXN_ROOT_PENALTY_ACCT_IDX( root_idx ) );
    1835        2704 :       penalty_treap = penalty_map_query( pack->penalty_treaps, penalty_acct, NULL );
    1836        2704 :       FD_TEST( penalty_treap );
    1837        2704 :       root = penalty_treap->penalty_treap;
    1838        2704 :       break;
    1839        2704 :     }
    1840      494622 :   }
    1841             : 
    1842      494622 :   for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
    1843      998490 :       iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1844             : 
    1845      503868 :     release_result_t ret = release_bit_reference( pack, ACCT_ITER_TO_PTR( iter ) );
    1846      503868 :     FD_PACK_BITSET_CLEARN( pack->bitset_rw_in_use, ret.clear_rw_bit );
    1847      503868 :     FD_PACK_BITSET_CLEARN( pack->bitset_w_in_use,  ret.clear_w_bit  );
    1848      503868 :   }
    1849             : 
    1850      494622 :   for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY );
    1851     1493814 :       iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1852      999192 :     if( FD_UNLIKELY( fd_pack_unwritable_contains( ACCT_ITER_TO_PTR( iter ) ) ) ) continue;
    1853             : 
    1854      504570 :     release_result_t ret = release_bit_reference( pack, ACCT_ITER_TO_PTR( iter ) );
    1855      504570 :     FD_PACK_BITSET_CLEARN( pack->bitset_rw_in_use, ret.clear_rw_bit );
    1856      504570 :     FD_PACK_BITSET_CLEARN( pack->bitset_w_in_use,  ret.clear_w_bit  );
    1857      504570 :   }
    1858      494622 :   expq_remove( pack->expiration_q, containing->expq_idx );
    1859      494622 :   containing->root = FD_ORD_TXN_ROOT_FREE;
    1860      494622 :   treap_ele_remove( root, containing, pack->pool );
    1861      494622 :   trp_pool_ele_release( pack->pool, containing );
    1862      494622 :   sig2txn_remove( pack->signature_map, in_tbl );
    1863      494622 :   pack->pending_txn_cnt--;
    1864             : 
    1865      494622 :   if( FD_UNLIKELY( penalty_treap && treap_ele_cnt( root )==0UL ) ) {
    1866           0 :     penalty_map_remove( pack->penalty_treaps, penalty_treap );
    1867           0 :   }
    1868             : 
    1869      494622 :   return 1;
    1870      494622 : }
    1871             : 
    1872             : 
    1873             : int
    1874             : fd_pack_verify( fd_pack_t * pack,
    1875           0 :                 void      * scratch ) {
    1876             :   /* Invariants:
    1877             :      sig2txn_query has exact same contents as all treaps combined
    1878             :      root matches treap
    1879             :      Keys of acct_to_bitset is exactly union of all accounts in all
    1880             :             transactions in treaps, with ref counted appropriately
    1881             :      bits in bitset_avail is complement of bits allocated in
    1882             :             acct_to_bitset
    1883             :      expires_at consistent between treap, prq */
    1884             : 
    1885             :   /* TODO:
    1886             :      bitset_{r}w_in_use = bitset_map_query( everything in acct_in_use that doesn't have FD_PACK_IN_USE_BIT_CLEARED )
    1887             :      use_by_bank does not contain duplicates
    1888             :      use_by_bank consistent with acct_in_use
    1889             :      bitset_w_in_use & bitset_rw_in_use == bitset_w_in_use
    1890             :      elements in pool but not in a treap have root set to free
    1891             :      all penalty treaps have at least one transaction */
    1892           0 : #define VERIFY_TEST( cond, ... ) do {   \
    1893           0 :     if( FD_UNLIKELY( !(cond) ) ) {      \
    1894           0 :       FD_LOG_WARNING(( __VA_ARGS__ ));  \
    1895           0 :       return -(__LINE__);               \
    1896           0 :     }                                   \
    1897           0 :   } while( 0 )
    1898             : 
    1899           0 :   ulong max_acct_in_treap  = pack->pack_depth * FD_TXN_ACCT_ADDR_MAX;
    1900           0 :   int lg_acct_in_trp = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_treap  ) );
    1901           0 :   void * _bitset_map_copy = scratch;
    1902           0 :   void * _bitset_map_orig = bitset_map_leave( pack->acct_to_bitset );
    1903           0 :   fd_memcpy( _bitset_map_copy, _bitset_map_orig, bitset_map_footprint( lg_acct_in_trp ) );
    1904             : 
    1905           0 :   fd_pack_bitset_acct_mapping_t * bitset_copy = bitset_map_join( _bitset_map_copy );
    1906             : 
    1907             :   /* Check that each bit is in exactly one place */
    1908           0 :   FD_PACK_BITSET_DECLARE( processed ); FD_PACK_BITSET_CLEAR( processed );
    1909           0 :   FD_PACK_BITSET_DECLARE( bit       ); FD_PACK_BITSET_CLEAR( bit       );
    1910           0 :   FD_PACK_BITSET_DECLARE( full      ); FD_PACK_BITSET_CLEAR( full      );
    1911             : 
    1912           0 :   if( FD_UNLIKELY( pack->bitset_avail[0]!=FD_PACK_BITSET_SLOWPATH ) ) return -1;
    1913           0 :   for( ulong i=1UL; i<=pack->bitset_avail_cnt; i++ ) {
    1914           0 :     FD_PACK_BITSET_CLEAR( bit );
    1915           0 :     FD_PACK_BITSET_SETN( bit, pack->bitset_avail[ i ] );
    1916           0 :     VERIFY_TEST( FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, processed, processed ),
    1917           0 :         "bit %hu in avail set twice", pack->bitset_avail[ i ] );
    1918           0 :     FD_PACK_BITSET_OR( processed, bit );
    1919           0 :   }
    1920             : 
    1921           0 :   ulong total_references = 0UL;
    1922           0 :   for( ulong i=0UL; i<bitset_map_slot_cnt( bitset_copy ); i++ ) {
    1923           0 :     if( !bitset_map_key_inval( bitset_copy[ i ].key ) ) {
    1924           0 :       VERIFY_TEST( bitset_copy[ i ].ref_cnt>0UL, "account address in table with 0 ref count" );
    1925             : 
    1926           0 :       total_references += bitset_copy[ i ].ref_cnt;
    1927             : 
    1928           0 :       FD_PACK_BITSET_CLEAR( bit );
    1929           0 :       FD_PACK_BITSET_SETN( bit, bitset_copy[ i ].bit );
    1930           0 :       VERIFY_TEST( FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, processed, processed ), "bit %hu used twice", bitset_copy[ i ].bit );
    1931           0 :       FD_PACK_BITSET_OR( processed, bit );
    1932           0 :     }
    1933           0 :   }
    1934           0 :   for( ulong i=0UL; i<FD_PACK_BITSET_MAX; i++ ) {
    1935           0 :     FD_PACK_BITSET_CLEAR( bit );
    1936           0 :     FD_PACK_BITSET_SETN( bit, i );
    1937           0 :     VERIFY_TEST( !FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, processed, processed ), "bit %lu missing", i );
    1938           0 :     FD_PACK_BITSET_SETN( full, i );
    1939           0 :   }
    1940             : 
    1941             : 
    1942           0 :   fd_pack_ord_txn_t  * pool = pack->pool;
    1943           0 :   treap_t * treaps[ 2 ] = { pack->pending, pack->pending_votes };
    1944           0 :   ulong txn_cnt = 0UL;
    1945             : 
    1946           0 :   for( ulong k=0UL; k<2; k++ ) {
    1947           0 :     treap_t * treap = treaps[ k ];
    1948             : 
    1949           0 :     for( treap_rev_iter_t _cur=treap_rev_iter_init( treap, pool ); !treap_rev_iter_done( _cur );
    1950           0 :         _cur=treap_rev_iter_next( _cur, pool ) ) {
    1951           0 :       txn_cnt++;
    1952           0 :       fd_pack_ord_txn_t const * cur = treap_rev_iter_ele_const( _cur, pool );
    1953           0 :       fd_txn_t const * txn = TXN(cur->txn);
    1954           0 :       fd_acct_addr_t const * accts   = fd_txn_get_acct_addrs( txn, cur->txn->payload );
    1955           0 :       fd_acct_addr_t const * alt_adj = cur->txn_e->alt_accts - fd_txn_account_cnt( txn, FD_TXN_ACCT_CAT_IMM );
    1956             : 
    1957           0 :       fd_ed25519_sig_t const * sig0 = fd_txn_get_signatures( txn, cur->txn->payload );
    1958             : 
    1959           0 :       fd_pack_sig_to_txn_t * in_tbl = sig2txn_query( pack->signature_map, sig0, NULL );
    1960           0 :       VERIFY_TEST( in_tbl, "signature missing from sig2txn" );
    1961           0 :       VERIFY_TEST( in_tbl->key==sig0, "signature in sig2txn inconsistent" );
    1962           0 :       VERIFY_TEST( (ulong)(cur->root)==k+1, "treap element had bad root" );
    1963           0 :       VERIFY_TEST( cur->expires_at>=pack->expire_before, "treap element expired" );
    1964             : 
    1965           0 :       fd_pack_expq_t const * eq = pack->expiration_q + cur->expq_idx;
    1966           0 :       VERIFY_TEST( eq->txn==cur, "expq inconsistent" );
    1967           0 :       VERIFY_TEST( eq->expires_at==cur->expires_at, "expq expires_at inconsistent" );
    1968             : 
    1969           0 :       FD_PACK_BITSET_DECLARE( complement );
    1970           0 :       FD_PACK_BITSET_COPY( complement, full );
    1971           0 :       for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
    1972           0 :           iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1973           0 :         fd_acct_addr_t acct = *ACCT_ITER_TO_PTR( iter );
    1974             : 
    1975           0 :         fd_pack_bitset_acct_mapping_t * q = bitset_map_query( bitset_copy, acct, NULL );
    1976           0 :         VERIFY_TEST( q, "account in transaction missing from bitset mapping" );
    1977           0 :         VERIFY_TEST( q->ref_cnt>0UL, "account in transaction ref_cnt already 0" );
    1978           0 :         q->ref_cnt--;
    1979           0 :         total_references--;
    1980             : 
    1981           0 :         FD_PACK_BITSET_CLEAR( bit );
    1982           0 :         FD_PACK_BITSET_SETN( bit, q->bit );
    1983           0 :         if( q->bit<FD_PACK_BITSET_MAX ) {
    1984           0 :           VERIFY_TEST( !FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, cur->rw_bitset, cur->rw_bitset ), "missing from rw bitset" );
    1985           0 :           VERIFY_TEST( !FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, cur->w_bitset,  cur->w_bitset ), "missing from w bitset" );
    1986           0 :         }
    1987           0 :         FD_PACK_BITSET_CLEARN( complement, q->bit );
    1988           0 :       }
    1989           0 :       VERIFY_TEST( FD_PACK_BITSET_INTERSECT4_EMPTY( complement, complement, cur->w_bitset,  cur->w_bitset ), "extra in w bitset" );
    1990             : 
    1991           0 :       for( fd_txn_acct_iter_t iter=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_READONLY );
    1992           0 :           iter!=fd_txn_acct_iter_end(); iter=fd_txn_acct_iter_next( iter ) ) {
    1993             : 
    1994           0 :         fd_acct_addr_t acct = *ACCT_ITER_TO_PTR( iter );
    1995           0 :         if( FD_UNLIKELY( fd_pack_unwritable_contains( &acct ) ) ) continue;
    1996           0 :         fd_pack_bitset_acct_mapping_t * q = bitset_map_query( bitset_copy, acct, NULL );
    1997           0 :         VERIFY_TEST( q, "account in transaction missing from bitset mapping" );
    1998           0 :         VERIFY_TEST( q->ref_cnt>0UL, "account in transaction ref_cnt already 0" );
    1999           0 :         q->ref_cnt--;
    2000           0 :         total_references--;
    2001             : 
    2002           0 :         FD_PACK_BITSET_CLEAR( bit );
    2003           0 :         FD_PACK_BITSET_SETN( bit, q->bit );
    2004           0 :         if( q->bit<FD_PACK_BITSET_MAX ) {
    2005           0 :           VERIFY_TEST( !FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, cur->rw_bitset, cur->rw_bitset ), "missing from rw bitset" );
    2006           0 :         }
    2007           0 :         FD_PACK_BITSET_CLEARN( complement, q->bit );
    2008           0 :       }
    2009           0 :       VERIFY_TEST( FD_PACK_BITSET_INTERSECT4_EMPTY( complement, complement, cur->rw_bitset,  cur->rw_bitset ), "extra in rw bitset" );
    2010           0 :     }
    2011           0 :   }
    2012             : 
    2013           0 :   bitset_map_leave( bitset_copy );
    2014             : 
    2015           0 :   VERIFY_TEST( total_references==0UL, "extra references in bitset mapping" );
    2016           0 :   VERIFY_TEST( txn_cnt==sig2txn_key_cnt( pack->signature_map ), "extra signatures in sig2txn" );
    2017             : 
    2018           0 :   bitset_map_join( _bitset_map_orig );
    2019             : 
    2020           0 :   ulong max_acct_in_flight = pack->bank_tile_cnt * (FD_TXN_ACCT_ADDR_MAX * pack->lim->max_txn_per_microblock + 1UL);
    2021           0 :   int lg_uses_tbl_sz = fd_ulong_find_msb( fd_ulong_pow2_up( 2UL*max_acct_in_flight ) );
    2022             : 
    2023           0 :   void * _acct_in_use_copy = scratch;
    2024           0 :   void * _acct_in_use_orig = acct_uses_leave( pack->acct_in_use );
    2025           0 :   fd_memcpy( _acct_in_use_copy, _acct_in_use_orig, acct_uses_footprint( lg_uses_tbl_sz ) );
    2026             : 
    2027           0 :   fd_pack_addr_use_t * acct_in_use_copy = acct_uses_join( _acct_in_use_copy );
    2028             : 
    2029           0 :   FD_PACK_BITSET_DECLARE(  w_complement );
    2030           0 :   FD_PACK_BITSET_DECLARE( rw_complement );
    2031           0 :   FD_PACK_BITSET_COPY(  w_complement, full );
    2032           0 :   FD_PACK_BITSET_COPY( rw_complement, full );
    2033             : 
    2034           0 :   FD_PACK_BITSET_DECLARE( rw_bitset );  FD_PACK_BITSET_COPY( rw_bitset, pack->bitset_rw_in_use );
    2035           0 :   FD_PACK_BITSET_DECLARE(  w_bitset );  FD_PACK_BITSET_COPY(  w_bitset, pack->bitset_w_in_use  );
    2036             : 
    2037             : 
    2038           0 :   ulong const EMPTY_MASK = ~(FD_PACK_IN_USE_WRITABLE | FD_PACK_IN_USE_BIT_CLEARED);
    2039             : 
    2040           0 :   for( ulong bank=0UL; bank<pack->bank_tile_cnt; bank++ ) {
    2041             : 
    2042           0 :     fd_pack_addr_use_t const * base = pack->use_by_bank[ bank ];
    2043           0 :     ulong bank_mask = 1UL << bank;
    2044             : 
    2045           0 :     for( ulong i=0UL; i<pack->use_by_bank_cnt[ bank ]; i++ ) {
    2046           0 :       fd_pack_addr_use_t * use = acct_uses_query( acct_in_use_copy, base[i].key, NULL );
    2047           0 :       VERIFY_TEST( use, "acct in use by bank not in acct_in_use, or in uses_by_bank twice" );
    2048             : 
    2049           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" );
    2050             : 
    2051           0 :       fd_pack_bitset_acct_mapping_t * q = bitset_map_query( pack->acct_to_bitset, base[i].key, NULL );
    2052             :       /* The normal case is that the acct->bit mapping is preserved
    2053             :          while in use by other transactions in the pending list.  This
    2054             :          might not always happen though.  It's okay for the mapping to
    2055             :          get deleted while the acct is in use, which is noted with
    2056             :          BIT_CLEARED.  If that is set, the mapping may not exist, or it
    2057             :          may have been re-created, perhaps with a different bit. */
    2058           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" );
    2059           0 :       else if( !(use->in_use_by & FD_PACK_IN_USE_BIT_CLEARED) ) {
    2060           0 :         FD_PACK_BITSET_CLEAR( bit );
    2061           0 :         FD_PACK_BITSET_SETN( bit, q->bit );
    2062           0 :         if( q->bit<FD_PACK_BITSET_MAX ) {
    2063           0 :           VERIFY_TEST( !FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, rw_bitset, rw_bitset ), "missing from rw bitset" );
    2064           0 :           if( use->in_use_by & FD_PACK_IN_USE_WRITABLE ) {
    2065           0 :             VERIFY_TEST( !FD_PACK_BITSET_INTERSECT4_EMPTY( bit, bit, w_bitset, w_bitset ), "missing from w bitset" );
    2066           0 :             FD_PACK_BITSET_CLEARN( w_complement, q->bit );
    2067           0 :           }
    2068           0 :         }
    2069           0 :         FD_PACK_BITSET_CLEARN( rw_complement, q->bit );
    2070           0 :       }
    2071           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" );
    2072             : 
    2073           0 :       use->in_use_by &= ~bank_mask;
    2074           0 :       if( !(use->in_use_by & EMPTY_MASK) ) acct_uses_remove( acct_in_use_copy, use );
    2075           0 :     }
    2076           0 :   }
    2077           0 :   VERIFY_TEST( acct_uses_key_cnt( acct_in_use_copy )==0UL, "stray uses in acct_in_use" );
    2078           0 :   VERIFY_TEST( FD_PACK_BITSET_INTERSECT4_EMPTY( rw_complement, rw_complement, rw_bitset,  rw_bitset ), "extra in rw bitset" );
    2079           0 :   VERIFY_TEST( FD_PACK_BITSET_INTERSECT4_EMPTY(  w_complement,  w_complement,  w_bitset,   w_bitset ), "extra in w bitset" );
    2080             : 
    2081           0 :   acct_uses_leave( acct_in_use_copy );
    2082             : 
    2083           0 :   acct_uses_join( _acct_in_use_orig );
    2084           0 :   return 0;
    2085           0 : }
    2086             : 
    2087           0 : void * fd_pack_leave ( fd_pack_t * pack ) { FD_COMPILER_MFENCE(); return (void *)pack; }
    2088           0 : void * fd_pack_delete( void      * mem  ) { FD_COMPILER_MFENCE(); return mem;          }

Generated by: LCOV version 1.14