LCOV - code coverage report
Current view: top level - ballet/txn - fd_txn.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 123 128 96.1 %
Date: 2024-11-13 11:58:15 Functions: 48 4199 1.1 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_ballet_txn_fd_txn_h
       2             : #define HEADER_fd_src_ballet_txn_fd_txn_h
       3             : 
       4             : /* The main structure this header defines is fd_txn_t, which represents a
       5             :    Solana transaction.  A transaction, like a SQL database transaction, is the
       6             :    unit of execution atomicity in Solana, i.e. intermediate state is never
       7             :    visible to other transactions, and a failure at any point in the transaction
       8             :    causes the entire transaction to be rolled back (other than charging the
       9             :    transaction fee).
      10             : 
      11             :    A transaction primarily consists of a list of instructions to execute in
      12             :    sequence.  The struct fd_txn_instr_t describes one instruction.  An instruction
      13             :    specifies the invocation of a smart contract with some specified data and
      14             :    accounts.  The name 'instruction' was a poor choice, (since on-chain code is
      15             :    composed of eBPF instructions and using the same word to refer to very
      16             :    different concepts is confusing) but it's too late to change.  Thinking of a
      17             :    transaction-level instruction as a 'command' might be more useful.
      18             : 
      19             :    The other major component of a transaction is a list of account addresses.
      20             :    The address of any account that is referenced by any instruction in the
      21             :    transaction must appear in the list.  The address of any signer (including
      22             :    the fee payer) must appear in the list.  An account address is sometimes
      23             :    called a pubkey since it has the same format as one, though it is not always
      24             :    a public key strictly speaking (i.e. a corresponding private key may not
      25             :    exist).  Each account address in the list has associated permissions flags:
      26             :    signer/not signer and writable/readonly.  All 4 combinations are possible.
      27             :    These flags declare the transaction's intention in accessing the account,
      28             :    similar to the `mode` field of fopen( ). */
      29             : 
      30             : #include "../fd_ballet_base.h"
      31             : 
      32             : #include "../ed25519/fd_ed25519.h"
      33             : 
      34             : /* FD_TXN_VLEGACY: the initial, pre-V0 transaction format. */
      35    30975699 : #define FD_TXN_VLEGACY ((uchar)0xFF)
      36             : /* FD_TXN_V0: The second transaction format.  Includes a version number and
      37             :    potentially some address lookup tables */
      38      310236 : #define FD_TXN_V0      ((uchar)0x00)
      39             : 
      40             : /* FD_TXN_SIGNATURE_SZ: The size (in bytes) of an Ed25519 signature. */
      41   369555276 : #define FD_TXN_SIGNATURE_SZ (64UL)
      42             : /* FD_TXN_PUBKEY_SZ: The size (in bytes) of an Ed25519 public key. */
      43             : #define FD_TXN_PUBKEY_SZ    (32UL)
      44             : /* FD_TXN_ACCT_ADDR_SZ: The size (in bytes) of a Solana account address.
      45             :    Account addresses are sometimes Ed25519 public keys, but they can also be
      46             :    the output of a SHA256 hash (program derived addresses and seeded accounts),
      47             :    or just hardcoded values (sysvars accounts).  It's important that all types
      48             :    of account addresses have this same size. */
      49  5454401559 : #define FD_TXN_ACCT_ADDR_SZ (32UL)
      50             : /* FD_TXN_BLOCKHASH_SZ: The size (in bytes) of a blockhash.  A blockhash is a
      51             :    SHA256 hash, giving a size of 256 bits = 32 bytes. */
      52    61370514 : #define FD_TXN_BLOCKHASH_SZ (32UL)
      53             : 
      54             : 
      55             : /* FD_TXN_SIG_MAX: The (inclusive) maximum number of signatures a transaction
      56             :    can have.  Note: for the current MTU size of 1232 B, the maximum that a
      57             :    valid transaction can have is 12 signatures. The most I've seen in practice
      58             :    is about 7.
      59             : 
      60             :    FD_TXN_ACTUAL_SIG_MAX: used to allocate arrays of signatures, pubkeys, etc.
      61             : 
      62             :    From the spec: "The Solana runtime verifies that the number of signatures
      63             :    [stored as a compact-u16] matches the number in the first 8 bits of the
      64             :    message header."
      65             :    Thus this value must live in the range where compact-u16 and uint8
      66             :    representations are identical, hence a max of 127. */
      67      221319 : #define FD_TXN_SIG_MAX               (127UL)
      68         324 : #define FD_TXN_ACTUAL_SIG_MAX        (12UL)
      69             : 
      70             : /* FD_TXN_ACCT_ADDR_MAX: The (inclusive) maximum number of account addresses
      71             :    that a transaction can have.  The spec only guarantees <= 256, but the
      72             :    current MTU of 1232 B restricts this to 35 account addresses.  An artificial
      73             :    limit of 64 is currently in place, but this is being changed to 128 in the
      74             :    near future (https://github.com/solana-labs/solana/issues/27241), so we'll
      75             :    use 128. */
      76             : /* https://github.com/anza-xyz/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/sdk/program/src/message/versions/v0/mod.rs#L139 */
      77       10308 : #define FD_TXN_ACCT_ADDR_MAX         (128UL)
      78             : 
      79             : /* FD_TXN_ADDR_TABLE_LOOKUP_MAX: The (inclusive) maximum number of address
      80             :    tables that this transaction references.  The spec is pretty sloppy about
      81             :    the maximum number allowed.  Since there's a maximum of 128 total accounts
      82             :    (including the fee payer) that the transaction can reference, if you have
      83             :    more than 127 table lookups, then you must have some from which you are not
      84             :    using any account.  Realistically, the current MTU of 1232 B restricts this
      85             :    to 33. FIXME: We should petition to limit this to approx 8. */
      86       25155 : #define FD_TXN_ADDR_TABLE_LOOKUP_MAX (127UL)
      87             : 
      88             : /* FD_TXN_INSTR_MAX: The (inclusive) maximum number of instructions a transaction
      89             :    can have.  As of Solana 1.15.0, this is limited to 64. */
      90         198 : #define FD_TXN_INSTR_MAX             (64UL)
      91             : 
      92             : 
      93             : /* FD_TXN_MAX_SZ: The maximum amount of memory (in bytes) that a fd_txn can
      94             :    take up, including the instruction array and any address tables.  The
      95             :    worst-case transaction is a V0 transaction with only two account
      96             :    addresses (a program and a fee payer), and tons of empty instructions (no
      97             :    accounts, no data) and as many address table lookups loading a single
      98             :    account as possible. */
      99          42 : #define FD_TXN_MAX_SZ                (852UL)
     100             : 
     101             : 
     102             : /* FD_TXN_MTU: The maximum size (in bytes, inclusive) of a serialized
     103             :    transaction. */
     104       92955 : #define FD_TXN_MTU                  (1232UL)
     105             : 
     106             : /* FD_TXN_MIN_SERIALIZED_SZ: The minimum size (in bytes) of a serialized
     107             :    transaction, using fd_txn_parse() verification rules. */
     108           0 : #define FD_TXN_MIN_SERIALIZED_SZ     (134UL)
     109             : 
     110             : /* BEGIN Agave limits */
     111             : 
     112             : /* "Maximum number of accounts that a transaction may lock.
     113             :     128 was chosen because it is the minimum number of accounts
     114             :     needed for the Neon EVM implementation."
     115             :    https://github.com/anza-xyz/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/sdk/src/transaction/sanitized.rs#L30 */
     116      226785 : #define MAX_TX_ACCOUNT_LOCKS         (128UL)
     117             : /* In the FD runtime, we've sized things assuming up to
     118             :    MAX_TX_ACCOUNT_LOCKS accounts per transaction. We rely on the txn
     119             :    parser to enforce this limit, up till the point of
     120             :    validate_account_locks(). If the txn parser bumps the account limit,
     121             :    then we might overflow in the runtime. */
     122             : FD_STATIC_ASSERT( MAX_TX_ACCOUNT_LOCKS==FD_TXN_ACCT_ADDR_MAX, num_accounts_per_txn );
     123             : 
     124             : /* END Agave limits */
     125             : 
     126             : 
     127             : /* A Solana transaction instruction, i.e. one command or step to execute in a
     128             :    transaction.
     129             : 
     130             :    An instruction tells the runtime to execute one on-chain program (smart
     131             :    contract) with some arguments (think argc, argv).  The arguments come in the
     132             :    form of binary data and/or accounts, each of which is variable-sized and
     133             :    optional.
     134             : 
     135             :    Note that instructions specify accounts by giving an index into the
     136             :    transaction-level list of account addresses.  This means there are
     137             :    essentially two layers of indirection: a 1 B index to a 32 B address which
     138             :    specifies an account. */
     139             : struct fd_txn_instr {
     140             :   /* program_id: The on-chain program that this instruction invokes,
     141             :      represented as the index of the program's account address in the
     142             :      containing transaction's list of account addresses. */
     143             :   uchar   program_id;
     144             :   uchar   _padding_reserved_1; /* explicitly declare what the compiler would
     145             :                                   insert anyways */
     146             : 
     147             :   /* acct_cnt: The number of accounts this instruction references.
     148             :      N.B. It is possible to pass > 256 accounts to an instruction, but not more
     149             :      than 256 unique accounts. */
     150             :   ushort  acct_cnt;
     151             : 
     152             :   /* data_sz: The size (in bytes) of the data passed to this instruction. The
     153             :      data itself is included in the transaction, so is limited to the overall
     154             :      transaction size. */
     155             :   ushort  data_sz;
     156             : 
     157             :   /* acct_off: The offset (relative to the start of the transaction) in bytes
     158             :      where the account address index array starts.  This array has size
     159             :      acct_cnt.
     160             : 
     161             :      Specifically, if uchar const * payload is a pointer to the first byte of
     162             :      the transaction data in the packet, then the array (payload+acct_off)[i]
     163             :      for i in [0, acct_cnt) gives all of the accounts passed to this
     164             :      instruction.  As with the program_id, these accounts are represented as
     165             :      indices into the transaction's list of account addresses.
     166             :      */
     167             :   ushort  acct_off;
     168             : 
     169             :   /* data_off: The offset (relative to the start of the transaction) in bytes
     170             :      where the instruction data array starts.  This array has size data_sz.
     171             : 
     172             :      Specifically, if uchar const * payload is a pointer to the first byte of
     173             :      the transaction data in the packet, then the array (payload+data_off)[i]
     174             :      for i in [0, data_sz) gives the binary data passed to this instruction. */
     175             :   ushort  data_off;
     176             : };
     177             : 
     178             : typedef struct fd_txn_instr fd_txn_instr_t;
     179             : 
     180             : 
     181             : /* fd_txn_t: A Solana transaction. As explained above, a transaction is mostly
     182             :    a list of instructions, but there are a few other major components:
     183             :    - a list of account addresses,
     184             :    - the hash of a recent block (used as a nonce and TTL), and
     185             :    - potentially (if it's a V2 transaction) some address lookup tables. */
     186             : struct fd_txn {
     187             :   /* transaction_version: The version number of this transaction. Currently
     188             :      must be one of { FD_TXN_VLEGACY, FD_TXN_V0 }. */
     189             :   uchar       transaction_version;
     190             : 
     191             :   /* signature_cnt: The number of signatures in this transaction. signature_cnt
     192             :      in [1, FD_TXN_SIG_MAX]. */
     193             :   uchar       signature_cnt;
     194             : 
     195             :   /* signature_off: The offset (relative to the start of the transaction) in
     196             :      bytes where the signatures start.
     197             : 
     198             :      Specifically, if uchar const * payload is a pointer to the first byte of
     199             :      the transaction data in the packet, then signature i starts at
     200             :      (payload+signature_off)[ FD_TXN_SIGNATURE_SZ*i ] for i in
     201             :      [0, signature_cnt).
     202             : 
     203             :      Note that signature_off is always 1 in current transaction versions. */
     204             :   ushort      signature_off;
     205             : 
     206             :   /* message_off: The offset (relative to the start of the transaction) in
     207             :      bytes where the 'message' starts.
     208             : 
     209             :      The message, which is the part of the packet covered by the signatures,
     210             :      spans from this offset to the end of the packet. */
     211             :   ushort      message_off;
     212             : 
     213             :   /* readonly_signed_cnt: Of the signature_cnt signatures, readonly_signed_cnt
     214             :      of them are read only. Since there must be a fee payer,
     215             :      readonly_signed_cnt in [0, signature_cnt) */
     216             :   uchar       readonly_signed_cnt;
     217             : 
     218             :   /* readonly_unsigned_cnt: Of the account addresses that don't have an
     219             :      accompanying signature, readonly_unsigned_cnt of them are read only.
     220             :      readonly_unsigned_cnt in [0, acct_addr_cnt-signature_cnt].  Excludes any
     221             :      accounts from address table lookups. */
     222             :   uchar       readonly_unsigned_cnt;
     223             : 
     224             :   /* acct_addr_cnt: The number of account addresses in this transaction.
     225             :      acct_addr_cnt in [1, FD_TXN_ACCT_ADDR_MAX].  Excludes any accounts from
     226             :      address table lookups. */
     227             :   ushort      acct_addr_cnt;
     228             : 
     229             :   /* acct_addr_off: The offset (relative to the start of the transaction) in
     230             :      bytes where the account addresses start.
     231             : 
     232             :      Specifically, if uchar const * payload is a pointer to the first byte of
     233             :      the transaction data in the packet, then the array
     234             :      (payload+acct_addr_off)[ FD_TXN_ACCT_ADDR_SZ*i ] for i in [0, account_cnt)
     235             :      gives all of the account addresses in this transaction.  Since
     236             :      (payload+acct_addr_off) points inside the packet, it should be treated as
     237             :      pointing to unaligned data.
     238             : 
     239             :      The order of these addresses is important, because it determines the
     240             :      "permission flags" for the account in this transaction.
     241             :      Accounts ordered:
     242             :                                           Index Range                                 |   Signer?    |  Writeable?
     243             :      ---------------------------------------------------------------------------------|--------------|-------------
     244             :       [0,                                     signature_cnt - readonly_signed_cnt)    |  signer      |   writable
     245             :       [signature_cnt - readonly_signed_cnt,   signature_cnt)                          |  signer      |   readonly
     246             :       [signature_cnt,                         acct_addr_cnt - readonly_unsigned_cnt)  |  not signer  |   writable
     247             :       [acct_addr_cnt - readonly_unsigned_cnt, acct_addr_cnt)                          |  not signer  |   readonly
     248             :      */
     249             :   ushort      acct_addr_off;
     250             : 
     251             :   /* recent_blockhash_off: The offset (relative to the start of the
     252             :      transaction) in bytes where the recent blockhash starts.
     253             : 
     254             :      Specifically, if uchar const * payload is a pointer to the first byte of
     255             :      the transaction data in the packet, then (payload+recent_blockhash_off) is
     256             :      a pointer to the blockhash. Since the resulting pointer points inside the
     257             :      packet, it should be treated as pointing to unaligned data. In practice,
     258             :      recent_blockhash_off is 5 or 6 (mod 32). */
     259             :   ushort      recent_blockhash_off;
     260             : 
     261             :   /* addr_table_lookup_cnt: The number of address lookup tables this
     262             :      transaction contains.  Must be 0 if transaction_version==FD_TXN_VLEGACY.
     263             :      addr_table_lookup_cnt in [0, FD_TXN_ADDR_TABLE_LOOKUP_MAX]. */
     264             :   uchar       addr_table_lookup_cnt;
     265             : 
     266             :   /* addr_table_adtl_writable_cnt: The total number of writable account
     267             :      addresses across all of the address table lookups.
     268             :      addr_table_adtl_writable_cnt in [0, addr_table_adtl_cnt]. */
     269             :   uchar       addr_table_adtl_writable_cnt;
     270             : 
     271             :   /* addr_table_adtl_cnt: The total number of account addresses summed across
     272             :      all the address lookup tables. addr_table_adtl_cnt in
     273             :      [0, FD_TXN_ADDT_ADDR_MAX - acct_addr_cnt]. Since acct_addr_cnt > 0,
     274             :      addr_table_adtl_cnt < 256. */
     275             :   uchar      addr_table_adtl_cnt;
     276             :   uchar      _padding_reserved_1; /* explicit padding the compiler would have
     277             :                                      inserted anyways */
     278             : 
     279             :   /* From the address table lookups, we can add the following to the above table
     280             :                                                 Index Range                                         |   Signer?    |  Writeable?
     281             :      -----------------------------------------------------------------------------------------------|--------------|-------------
     282             :      ...
     283             :       [acct_addr_cnt,                                acct_addr_cnt + addr_table_adtl_writable_cnt)  |  not signer  |   writable
     284             :       [acct_addr_cnt + addr_table_adtl_writable_cnt, acct_addr_cnt + addr_table_adtl_cnt)           |  not signer  |   readonly
     285             :       */
     286             : 
     287             :   /* instr_cnt: The number of instructions in this transaction.
     288             :      instr_cnt in [0, FD_TXN_INSTR_MAX]. */
     289             :   ushort      instr_cnt;
     290             : 
     291             :   /* instr: The array of instructions in this transaction. It's a "flexible array
     292             :      member" since C does not allow the pretty typical 0-len array at the end
     293             :      of the struct trick.
     294             :      Indexed [0, instr_cnt). */
     295             :   fd_txn_instr_t instr[ ];
     296             : 
     297             :   /* Logically, there's another field here:
     298             :      address_tables: The address tables this transaction imports and which
     299             :      accounts from them are selected for inclusion in this transaction's
     300             :      overall list of accounts. Indexed [0, addr_table_lookup_cnt).
     301             :   fd_txn_acct_addr_lut_t address_tables[ ];
     302             :      To access it, call fd_txn_get_address_tables( ). */
     303             : 
     304             : };
     305             : 
     306             : typedef struct fd_txn fd_txn_t;
     307             : 
     308             : /* fd_txn_acct_addr_lut: An on-chain address lookup table. Solana added this to
     309             :    the Transaction v2 spec in order to allow a transaction to reference more
     310             :    accounts. This struct specifies which account addresses from an on-chain
     311             :    list should be selected to include in the list of account addresses
     312             :    available to instructions in this transaction */
     313             : struct fd_txn_acct_addr_lut {
     314             :   /* addr_off: The offset (relative to the start of the transaction) in bytes
     315             :      where the address of the account containing the list of to load is stored.
     316             : 
     317             :      Specifically, if uchar const * payload is a pointer to the first byte of
     318             :      the transaction data in the packet, then
     319             :      (fd_txn_acct_addr_t*)(payload+addr_off) is a pointer to the account
     320             :      address.  Since (payload+acct_addr_off) points inside the packet, it
     321             :      should be treated as pointing to unaligned data. */
     322             :   ushort addr_off;
     323             : 
     324             :   /* writable_cnt: The number of account addresses this LUT selects as writable
     325             :      from the on-chain list. */
     326             :   uchar  writable_cnt;
     327             :   /* readonly_cnt: The number of account addresses this LUT selects as read
     328             :      only from the on-chain list. */
     329             :   uchar  readonly_cnt;
     330             : 
     331             :   /* writable_off: The offset (relative to the start of the transaction) in
     332             :      bytes where the writable account indices begins.
     333             : 
     334             :      Specifically, if uchar const * payload is a pointer to the first byte of
     335             :      the transaction data in the packet, then (payload+writable_off)[i] for i
     336             :      in [0, writable_cnt) gives the indices into the on-chain list that are
     337             :      selected for inclusion in this transaction's list of account addresses as
     338             :      writable accounts. */
     339             :   ushort writable_off;
     340             : 
     341             :   /* readonly_off: The offset (relative to the start of the transaction) in
     342             :      bytes where the read only account indices begins.
     343             : 
     344             :      Specifically, if uchar const * payload is a pointer to the first byte of
     345             :      the transaction data in the packet, then (payload+readonly_off)[i] for i
     346             :      in [0, readonly_cnt) gives the indices into the on-chain list that are
     347             :      selected for inclusion in this transaction's list of account addresses as
     348             :      read only accounts. */
     349             :   ushort readonly_off;
     350             : };
     351             : 
     352             : typedef struct fd_txn_acct_addr_lut fd_txn_acct_addr_lut_t;
     353             : 
     354       87783 : #define FD_TXN_PARSE_COUNTERS_RING_SZ (32UL)
     355             : 
     356             : /* Counters for collecting some metrics about the outcome of parsing
     357             :    transactions */
     358             : struct fd_txn_parse_counters {
     359             :   /* success_cnt: the number of times a transaction parsed successfully */
     360             :   ulong success_cnt;
     361             :   /* failure_cnt: the number of times a transaction was ill-formed and failed
     362             :      to parse for any reason */
     363             :   ulong failure_cnt;
     364             :   /* failure_ring: some information about the causes of recent transaction
     365             :      parsing failures.  Specifically, the line of code which detected that the
     366             :      ith malformed transaction was malformed maps to
     367             :      failure_ring[ i%FD_TXN_PARSE_COUNTERS_RING_SZ ] (where i starts at 0), and the
     368             :      last instance mapping to each element of the array is the one that is
     369             :      actually present.  If fewer than FD_TXN_PARSE_COUNTERS_RING_SZ failures have
     370             :      occurred, the contents of some entries in this array are undefined. */
     371             :   ulong failure_ring[ FD_TXN_PARSE_COUNTERS_RING_SZ ];
     372             : };
     373             : typedef struct fd_txn_parse_counters fd_txn_parse_counters_t;
     374             : 
     375             : FD_PROTOTYPES_BEGIN
     376             : /* fd_txn_get_address_tables: Returns the array of address tables in this
     377             :    transaction.  This depends on the value of txn->instr_cnt being correct.  The
     378             :    lifetime of the returned pointer is the same as the fd_txn_t pointer passed
     379             :    as an argument, so it's not necessary to free the returned pointer
     380             :    separately.  Treat it as if this function returned a pointer to a member of
     381             :    the struct.  Suppose x=fd_txn_get_address_tables( txn ), then x[ i ] is valid
     382             :    for i in [0, txn->addr_table_lookup_cnt ). */
     383             : static inline fd_txn_acct_addr_lut_t *
     384    61323720 : fd_txn_get_address_tables( fd_txn_t * txn ) {
     385    61323720 :   return (fd_txn_acct_addr_lut_t *)(txn->instr + txn->instr_cnt);
     386    61323720 : }
     387             : 
     388             : static inline fd_txn_acct_addr_lut_t const *
     389       10893 : fd_txn_get_address_tables_const( fd_txn_t const * txn ) {
     390       10893 :   return (fd_txn_acct_addr_lut_t const *)(txn->instr + txn->instr_cnt);
     391       10893 : }
     392             : 
     393             : /* fd_acct_addr_t: An Solana account address, which may be an Ed25519
     394             :    public key, a SHA256 hash from a program derived address, a hardcoded
     395             :    sysvar, etc.  This type does not imply any alignment. */
     396             : union fd_acct_addr {
     397             :   uchar b[FD_TXN_ACCT_ADDR_SZ];
     398             : };
     399             : typedef union fd_acct_addr fd_acct_addr_t;
     400             : 
     401             : /* fd_txn_get_{signatures, acct_addrs}: Returns the array of Ed25519
     402             :    signatures or account addresses (commonly, yet imprecisely called
     403             :    pubkeys), respectively, in `payload`, the serialization of the
     404             :    transaction described by `txn`.  The number of signatures is seen in
     405             :    `txn->signature_cnt` and the number of account addresses is in
     406             :    `txn->acct_addr_cnt`.
     407             : 
     408             :    The lifetime of the returned signature is the lifetime of `payload`.
     409             :    Expect the returned pointer to point to memory with no particular
     410             :    alignment.  U.B. If `payload` and `txn` were not arguments to a valid
     411             :    `fd_txn_parse` call or if either was modified after the parse call.
     412             :    */
     413             : static inline fd_ed25519_sig_t const *
     414             : fd_txn_get_signatures( fd_txn_t const * txn,
     415    39734235 :                        void     const * payload ) {
     416    39734235 :    return (fd_ed25519_sig_t const *)((ulong)payload + (ulong)txn->signature_off);
     417    39734235 : }
     418             : 
     419             : static inline fd_acct_addr_t const *
     420             : fd_txn_get_acct_addrs( fd_txn_t const * txn,
     421    40292547 :                        void     const * payload ) {
     422    40292547 :   return (fd_acct_addr_t const *)((ulong)payload + (ulong)txn->acct_addr_off);
     423    40292547 : }
     424             : 
     425             : static inline uchar const *
     426             : fd_txn_get_recent_blockhash( fd_txn_t const * txn,
     427           0 :                              void     const * payload ) {
     428           0 :   return (uchar const *)((ulong)payload + (ulong)txn->recent_blockhash_off);
     429           0 : }
     430             : 
     431             : static inline uchar const *
     432             : fd_txn_get_instr_accts( fd_txn_instr_t const * instr,
     433        1905 :                         void           const * payload ) {
     434        1905 :   return (uchar const *)((ulong)payload + (ulong)instr->acct_off);
     435        1905 : }
     436             : 
     437             : static inline uchar const *
     438             : fd_txn_get_instr_data( fd_txn_instr_t const * instr,
     439       22845 :                        void           const * payload ) {
     440       22845 :   return (uchar const *)((ulong)payload + (ulong)instr->data_off);
     441       22845 : }
     442             : 
     443             : /* fd_txn_align returns the alignment in bytes required of a region of
     444             :    memory to be used as a fd_txn_t.  It is the same as
     445             :    alignof(fd_txn_t). */
     446             : static inline ulong
     447      108786 : fd_txn_align( void ) {
     448      108786 :   return alignof(fd_txn_t);
     449      108786 : }
     450             : 
     451             : /* fd_txn_footprint: Returns the total size of txn, including the
     452             :    instructions and the address tables (if any). */
     453             : static inline ulong
     454             : fd_txn_footprint( ulong instr_cnt,
     455    88260219 :                   ulong addr_table_lookup_cnt ) {
     456    88260219 :   return sizeof(fd_txn_t) + instr_cnt*sizeof(fd_txn_instr_t) + addr_table_lookup_cnt*sizeof(fd_txn_acct_addr_lut_t);
     457    88260219 : }
     458             : 
     459             : 
     460             : /* Each account address in a transaction has 3 independent binary
     461             :    properties:
     462             :    -  readonly/writable: this is enforced in the runtime, but a
     463             :        transaction fails if it tries to modify the contents of an
     464             :        account it marks as readonly
     465             :    -  signer/nonsigner: the sigverify tile ensures that the transaction
     466             :        has been validly signed by the key associated to each account
     467             :        address marked as a signer
     468             :    -  immediate/address lookup table: account addresses can come from
     469             :        the transaction itself ("immediate"), which is the only option
     470             :        for legacy transactions, or from an address lookup table
     471             : 
     472             :    For example, the fee payer must be writable, a signer, and immediate.
     473             : 
     474             :    From these properties, we can make categories of account addresses
     475             :    for counting and iterating over account addresses.  Since these
     476             :    properties can be set independently, it would seem to give us 2*2*2=8
     477             :    categories of accounts based on the properties, but account addresses
     478             :    that come from an address lookup table cannot be signers, giving 6
     479             :    raw categories instead of 8.
     480             : 
     481             :    The individual types of accounts are defined as bitflags so that
     482             :    combination categories can be created easily, e.g. all readonly
     483             :    accounts or all signers. */
     484             : 
     485             : /*                                                        Signer?   Writable?   Source? */
     486   162696846 : #define FD_TXN_ACCT_CAT_WRITABLE_SIGNER         0x01  /*    Yes        Yes        imm   */
     487   162696846 : #define FD_TXN_ACCT_CAT_READONLY_SIGNER         0x02  /*    Yes        No         imm   */
     488   162750399 : #define FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM  0x04  /*    No         Yes        imm   */
     489   162750399 : #define FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM  0x08  /*    No         No         imm   */
     490   162696846 : #define FD_TXN_ACCT_CAT_WRITABLE_ALT            0x10  /*    No         Yes       lookup */
     491   162696846 : #define FD_TXN_ACCT_CAT_READONLY_ALT            0x20  /*    No         No        lookup */
     492             : 
     493             : /* Define some groupings for convenience.  In the
     494             :    table below, "Any" means "don't care" */
     495    66391152 : #define FD_TXN_ACCT_CAT_WRITABLE                0x15  /*   Any         Yes        Any   */
     496    39239676 : #define FD_TXN_ACCT_CAT_READONLY                0x2A  /*   Any         No         Any   */
     497    13573050 : #define FD_TXN_ACCT_CAT_SIGNER                  0x03  /*   Yes         Any       Any/imm*/
     498         384 : #define FD_TXN_ACCT_CAT_NONSIGNER               0x3C  /*   No          Any        Any   */
     499    40227036 : #define FD_TXN_ACCT_CAT_IMM                     0x0F  /*   Any         Any        imm   */
     500    13573050 : #define FD_TXN_ACCT_CAT_ALT                     0x30  /*   No          Any       lookup */
     501         384 : #define FD_TXN_ACCT_CAT_NONE                    0x00  /*      --- Empty set ---         */
     502         384 : #define FD_TXN_ACCT_CAT_ALL                     0x3F  /*   Any         Any        Any   */
     503             : 
     504             : /* fd_txn_account_cnt: Returns the number of accounts referenced by this
     505             :    transaction that have the property specified by include_category.
     506             :    txn must be a pointer to a valid transaction.  include_cat must be
     507             :    one of the previously defined FD_TXN_ACCT_CAT_* values.  Ideally,
     508             :    include_cat should be a compile-time constant, in which case this
     509             :    function typically compiles to about 3 instructions. */
     510             : static inline ulong
     511             : fd_txn_account_cnt( fd_txn_t const * txn,
     512   162696462 :                     int              include_cat ) {
     513   162696462 :   ulong cnt = 0UL;
     514   162696462 :   if( include_cat & FD_TXN_ACCT_CAT_WRITABLE_SIGNER        ) cnt += (ulong)txn->signature_cnt - (ulong)txn->readonly_signed_cnt;
     515   162696462 :   if( include_cat & FD_TXN_ACCT_CAT_READONLY_SIGNER        ) cnt += (ulong)txn->readonly_signed_cnt;
     516   162696462 :   if( include_cat & FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM ) cnt += (ulong)txn->readonly_unsigned_cnt;
     517   162696462 :   if( include_cat & FD_TXN_ACCT_CAT_WRITABLE_ALT           ) cnt += (ulong)txn->addr_table_adtl_writable_cnt;
     518   162696462 :   if( include_cat & FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM )
     519   135547674 :     cnt += (ulong)txn->acct_addr_cnt - (ulong)txn->signature_cnt - (ulong)txn->readonly_unsigned_cnt;
     520   162696462 :   if( include_cat & FD_TXN_ACCT_CAT_READONLY_ALT           )
     521    27147249 :     cnt += (ulong)txn->addr_table_adtl_cnt - (ulong)txn->addr_table_adtl_writable_cnt;
     522             : 
     523   162696462 :   return cnt;
     524   162696462 : }
     525             : 
     526             : /* fd_txn_acct_iter_{init, next, end, idx}: These functions are used for
     527             :    iterating over the accounts in a transaction that have the property
     528             :    specified by include_cat.
     529             : 
     530             :    Example usage:
     531             : 
     532             :    fd_txn_acct_addr_t const * acct = fd_txn_get_acct_addrs( txn, payload );
     533             :    for( fd_txn_acct_iter_t i=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
     534             :          i!=fd_txn_acct_iter_end(); i=fd_txn_acct_iter_next( i ) ) {
     535             :      // Do something with acct[ fd_txn_acct_iter_idx( i ) ]
     536             :    }
     537             : 
     538             :    For fd_txn_acct_iter_init, txn must be a pointer to a valid
     539             :    transaction and include_cat must be one of the FD_TXN_ACCT_CAT_*
     540             :    values defined above (or a bitwise combination of them).  On
     541             :    completion, returns a value i such that fd_txn_acct_iter_idx( i ) is
     542             :    the index of the first account address meeting the specified
     543             :    criteria, or i==fd_txn_acct_iter_end() if there aren't any account
     544             :    addresses that meet the criteria.
     545             : 
     546             :    For fd_acct_iter_next, cur should be the current value of the
     547             :    iteration variable.  Advances the iteration variable such that
     548             :    fd_txn_acct_iter_idx( i ) is the index of the next account meeting
     549             :    the initially specified criteria, or i==fd_txn_acct_iter_end() if
     550             :    there aren't any more account addresses meeting the criteria.  It is
     551             :    undefined behavior to call fd_acct_iter_next with a value of cur not
     552             :    returned by a call to either fd_acct_iter_init or fd_acct_iter_next.
     553             :    It's also U.B. to call fd_acct_iter_next after fd_acct_iter_end has
     554             :    been returned.
     555             : 
     556             :    fd_txn_acct_iter_t should be treated as an opaque handle and not
     557             :    modified other than by using fd_txn_acc_iter_next.  You can peek and
     558             :    see that it's a ulong, so it fits in a register and doesn't need to
     559             :    be destroyed or cleaned up.  It's safe to save a fd_txn_acct_iter_t
     560             :    value to resume iteration later with the same transaction. */
     561             : 
     562             : typedef ulong fd_txn_acct_iter_t;
     563             : 
     564             : /* Account addresses are categorized into 6 categories, and all the
     565             :    account addresses for each category are stored contiguously.  This
     566             :    means that for any subset of the 6 categories that the user wants to
     567             :    iterate over, there are at most 3 disjoint ranges.
     568             : 
     569             :    For any iteration space I, we can choose 6 integers
     570             :    {start,count}_{0,1,2} so that
     571             :     I = [start0, start0+count0) U [start1, start1+count1)
     572             :                                 U [start2, start2+count2)
     573             :    Any empty intervals are represented as [0, 0).
     574             :    We store the control word as a single ulong with start0 in the low
     575             :    order bits.  Then the current account index can be retrieved by
     576             :    taking the low order byte, and the count remaining in the current
     577             :    interval is the second lowest byte.  We can update both in one
     578             :    instruction by subtracting 255. */
     579             : 
     580             : static inline fd_txn_acct_iter_t FD_FN_PURE
     581             : fd_txn_acct_iter_init( fd_txn_t const * txn,
     582    92164149 :                        int              include_cat ) {
     583             :   /* Our goal is to output something that looks like [start0, count0,
     584             :      start1, count1, start2, count2, 0, 0] from lowest order to highest.
     585             :      We construct the potentially 3 (start, count) pairs and then
     586             :      branchlessly get rid of any empty ones. */
     587    92164149 :   ulong control[3] = { 0 }; /* High 6 bytes of each stay element not touched */
     588    92164149 :   ulong i = (ulong)(-1L);   /* So that it is 0 post increment */
     589             : 
     590             :   /* Make references more convenient.  Dead code elimination seems to
     591             :      take care of the unneeded ones. */
     592    92164149 :   ulong s = txn->signature_cnt;
     593    92164149 :   ulong q = txn->readonly_signed_cnt;
     594    92164149 :   ulong r = txn->readonly_unsigned_cnt;
     595    92164149 :   ulong a = txn->acct_addr_cnt;
     596    92164149 :   ulong t = txn->addr_table_adtl_cnt;
     597    92164149 :   ulong u = txn->addr_table_adtl_writable_cnt;
     598             : 
     599             :   /* All the branches here should be known at compile time. */
     600             :   /* If WRITABLE_SIGNER is included, then f>>1 is 0, so the second
     601             :      branch will always be true, setting control[0]=0. */
     602    92164149 : # define INCLUDE_RANGE(f, start, cnt)                        \
     603   552984894 :   if( include_cat & (f) ) {                                  \
     604   276271695 :     if( !(include_cat & ((f)>>1) ) ) control[ ++i ]=(start); \
     605   276271695 :     control[ i ] += (cnt)<<8;                                \
     606   276271695 :   }
     607             : 
     608    92164149 :   INCLUDE_RANGE( FD_TXN_ACCT_CAT_WRITABLE_SIGNER,          0, s-q   );
     609    92164149 :   INCLUDE_RANGE( FD_TXN_ACCT_CAT_READONLY_SIGNER,        s-q, q     );
     610    92164149 :   INCLUDE_RANGE( FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM,   s, a-r-s );
     611    92164149 :   INCLUDE_RANGE( FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM, a-r, r     );
     612    92164149 :   INCLUDE_RANGE( FD_TXN_ACCT_CAT_WRITABLE_ALT,             a, u     );
     613    92164149 :   INCLUDE_RANGE( FD_TXN_ACCT_CAT_READONLY_ALT,           a+u, t-u   );
     614    92164149 : # undef INCLUDE_RANGE
     615             : 
     616             :   /* We now need to delete the empty intervals (if any). */
     617    92164149 :   ulong control0 = control[0];
     618    92164149 :   ulong control1 = control[1];
     619    92164149 :   ulong control2 = control[2];
     620             : 
     621    92164149 :   int control2_empty = !(control2&0xFF00UL);
     622    92164149 :   control2 = fd_ulong_if( control2_empty, 0UL,      control2 );
     623             : 
     624    92164149 :   int control1_empty = !(control1&0xFF00UL);
     625    92164149 :   control1 = fd_ulong_if( control1_empty, control2, control1 );
     626    92164149 :   control2 = fd_ulong_if( control1_empty, 0UL,      control2 );
     627             : 
     628    92164149 :   int control0_empty = !(control0&0xFF00UL);
     629    92164149 :   control0 = fd_ulong_if( control0_empty, control1, control0 );
     630    92164149 :   control1 = fd_ulong_if( control0_empty, control2, control1 );
     631    92164149 :   control2 = fd_ulong_if( control0_empty, 0UL,      control2 );
     632             : 
     633    92164149 :   return control0 | (control1<<16) | (control2<<32);
     634    92164149 : }
     635             : 
     636             : static inline fd_txn_acct_iter_t FD_FN_CONST
     637    68519679 : fd_txn_acct_iter_next( fd_txn_acct_iter_t cur ) {
     638    68519679 :   cur = cur + 0x0001UL - 0x0100UL; /* Increment low byte, decrement count */
     639             :   /* Move to the next interval if we're done with this one. */
     640    68519679 :   return fd_ulong_if( cur&0xFF00UL, cur, cur>>16 );
     641    68519679 : }
     642             : 
     643           0 : static inline fd_txn_acct_iter_t FD_FN_CONST fd_txn_acct_iter_end( void                   ) { return 0UL;          }
     644    68519691 : static inline ulong              FD_FN_CONST fd_txn_acct_iter_idx( fd_txn_acct_iter_t cur ) { return cur & 0xFFUL; }
     645             : 
     646             : /* fd_txn_parse_core: Parses a transaction from the canonical encoding, i.e.
     647             :    the format used on the wire.
     648             : 
     649             :    Payload points to the first byte of encoded transaction, e.g. the
     650             :    first byte of the UDP/Quic payload if the transaction comes from the
     651             :    network.  The encoded transaction must occupy exactly [payload,
     652             :    payload+payload_sz), i.e. this method will read no more than
     653             :    payload_sz bytes from payload, but it will reject the transaction if
     654             :    it contains extra padding at the end or continues past
     655             :    payload+payload_sz.  payload_sz <= FD_TXN_MTU.
     656             : 
     657             :    out_buf is the memory where the parsed transaction will be stored.
     658             :    out_buf must have room for at least FD_TXN_MAX_SZ bytes.
     659             : 
     660             :    Returns the total size of the resulting fd_txn struct on success and
     661             :    0 on failure.  On failure, the contents of out_buf are undefined,
     662             :    although nothing will be written beyond FD_TXN_MAX_SZ bytes.
     663             : 
     664             :    If counters_opt is non-NULL, some counters about the result of the
     665             :    parsing process will be accumulated into the struct pointed to by
     666             :    counters_opt.  Note: The returned txn object is not self-contained
     667             :    since it refers to byte ranges inside the payload.
     668             : 
     669             :    payload_sz_opt, if supplied, gets filled with the total bytes this txn
     670             :    uses (allowing for walking of an entry/microblock). If it is not supplied, the
     671             :    parse will return an error if the payload_sz does not exactly match. */
     672             : 
     673             : ulong
     674             : fd_txn_parse_core( uchar const             * payload,
     675             :                    ulong                     payload_sz,
     676             :                    void                    * out_buf,
     677             :                    fd_txn_parse_counters_t * counters_opt,
     678             :                    ulong *                   payload_sz_opt );
     679             : 
     680             : 
     681             : /* fd_txn_parse: Convenient wrapper around fd_txn_parse_core that eliminates some optional arguments */
     682             : static inline ulong
     683    61357776 : fd_txn_parse( uchar const * payload, ulong payload_sz, void * out_buf, fd_txn_parse_counters_t * counters_opt ) {
     684    61357776 :   return fd_txn_parse_core( payload, payload_sz, out_buf, counters_opt, NULL );
     685    61357776 : }
     686             : 
     687             : /* fd_txn_is_writable: Is the account at the supplied index writable
     688             : 
     689             :      Accounts ordered:
     690             :                                           Index Range                                 |   Signer?    |  Writeable?
     691             :      ---------------------------------------------------------------------------------|--------------|-------------
     692             :       [0,                                     signature_cnt - readonly_signed_cnt)    |  signer      |   writable
     693             :       [signature_cnt,                         acct_addr_cnt - readonly_unsigned_cnt)  |  not signer  |   writable
     694             : */
     695             : 
     696             : static inline int
     697       82524 : fd_txn_is_writable( fd_txn_t const * txn, int idx ) {
     698       82524 :   if (txn->transaction_version == FD_TXN_V0 && idx >= txn->acct_addr_cnt) {
     699       25017 :     if (idx < (txn->acct_addr_cnt + txn->addr_table_adtl_writable_cnt)) {
     700       16731 :       return 1;
     701       16731 :     }
     702        8286 :     return 0;
     703       25017 :   }
     704             : 
     705       57507 :   if (idx < (txn->signature_cnt - txn->readonly_signed_cnt))
     706       41088 :     return 1;
     707       16419 :   if ((idx >= txn->signature_cnt) & (idx < (txn->acct_addr_cnt - txn->readonly_unsigned_cnt)))
     708        5763 :     return 1;
     709             : 
     710       10656 :   return 0;
     711       16419 : }
     712             : 
     713             : /* fd_txn_is_signer: Is the account at the supplied index a signer
     714             : 
     715             :      Accounts ordered:
     716             :                                           Index Range                                 |   Signer?    |  Writeable?
     717             :      ---------------------------------------------------------------------------------|--------------|-------------
     718             :       [0,                                     signature_cnt - readonly_signed_cnt)    |  signer      |   writable
     719             :       [signature_cnt - readonly_signed_cnt,   signature_cnt)                          |  signer      |   readonly
     720             : */
     721             : static inline int
     722       36387 : fd_txn_is_signer( fd_txn_t const * txn, int idx ) {
     723       36387 :   return idx < txn->signature_cnt;
     724       36387 : }
     725             : 
     726             : FD_PROTOTYPES_END
     727             : 
     728             : #endif /* HEADER_fd_src_ballet_txn_fd_txn_h */

Generated by: LCOV version 1.14