LCOV - code coverage report
Current view: top level - ballet/txn - fd_txn.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 142 147 96.6 %
Date: 2026-09-17 04:28:31 Functions: 78 8037 1.0 %

          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    30956724 : #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      572904 : #define FD_TXN_V0      ((uchar)0x00)
      39             : /* FD_TXN_V1: The third transaction format ("Transaction V1").
      40             :    See https://github.com/solana-foundation/solana-improvement-documents/pull/385
      41             : 
      42             :    This format removes support for address lookup tables and is the
      43             :    only transaction format that supports an MTU greater than 1232
      44             :    bytes. */
      45       94683 : #define FD_TXN_V1      ((uchar)0x01)
      46             : 
      47             : /* FD_TXN_SIGNATURE_SZ: The size (in bytes) of an Ed25519 signature. */
      48    61504597 : #define FD_TXN_SIGNATURE_SZ (64UL)
      49             : /* FD_TXN_PUBKEY_SZ: The size (in bytes) of an Ed25519 public key. */
      50             : #define FD_TXN_PUBKEY_SZ    (32UL)
      51             : /* FD_TXN_ACCT_ADDR_SZ: The size (in bytes) of a Solana account address.
      52             :    Account addresses are sometimes Ed25519 public keys, but they can also be
      53             :    the output of a SHA256 hash (program derived addresses and seeded accounts),
      54             :    or just hardcoded values (sysvars accounts).  It's important that all types
      55             :    of account addresses have this same size. */
      56   785334076 : #define FD_TXN_ACCT_ADDR_SZ (32UL)
      57             : /* FD_TXN_BLOCKHASH_SZ: The size (in bytes) of a blockhash.  A blockhash is a
      58             :    SHA256 hash, giving a size of 256 bits = 32 bytes. */
      59    61345470 : #define FD_TXN_BLOCKHASH_SZ (32UL)
      60             : 
      61             : 
      62             : /* FD_TXN_SIG_MAX: The (inclusive) maximum number of signatures a transaction
      63             :    can have.
      64             : 
      65             :    For V0 transactions, which have an MTU of 1232 B, the maximum signatures
      66             :    that can fit in the MTU is 12.
      67             : 
      68             :    For V1 transactions, the spec explicitly limits the maximum number of
      69             :    signatures to 12. */
      70        6675 : #define FD_TXN_SIG_MAX (12UL)
      71             : 
      72             : /* FD_TXN_ACCT_ADDR_MAX: The (inclusive) maximum number of account addresses
      73             :    that a transaction can have.
      74             : 
      75             :    The account lock limit currently limits this to 64. */
      76      255525 : #define FD_TXN_ACCT_ADDR_MAX (64UL)
      77             : 
      78             : /* FD_TXN_ADDR_TABLE_LOOKUP_MAX: The (inclusive) maximum number of address
      79             :    tables that this transaction references.  The spec is pretty sloppy about
      80             :    the maximum number allowed.  Since there's a maximum of 128 total accounts
      81             :    (including the fee payer) that the transaction can reference, if you have
      82             :    more than 127 table lookups, then you must have some from which you are not
      83             :    using any account.  Realistically, the current MTU of 1232 B restricts this
      84             :    to 33. FIXME: We should petition to limit this to approx 8. */
      85       25155 : #define FD_TXN_ADDR_TABLE_LOOKUP_MAX (127UL)
      86             : 
      87             : /* FD_TXN_INSTR_MAX: The (inclusive) maximum number of instructions a transaction
      88             :    can have. */
      89        6531 : #define FD_TXN_INSTR_MAX             (64UL)
      90             : 
      91             : /* FD_TXN_INSTR_ACCT_MAX: The (inclusive) maximum number of accounts a
      92             :    single instruction can reference.
      93             :    https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/transaction-context/src/lib.rs#L17 */
      94           6 : #define FD_TXN_INSTR_ACCT_MAX        (255UL)
      95             : 
      96             : 
      97             : /* FD_TXN_MAX_SZ: The maximum amount of memory (in bytes) that a fd_txn can
      98             :    take up, including the instruction array and any address tables.  The
      99             :    worst-case transaction is a V0 transaction with only two account
     100             :    addresses (a program and a fee payer), and tons of empty instructions (no
     101             :    accounts, no data) and as many address table lookups loading a single
     102             :    account as possible.
     103             : 
     104             :    Worst-case V0 transaction: only 2 accounts, 64 empty instructions
     105             :    (no accounts, no data), 24 address lookup table lookups loading
     106             :    a single account:
     107             :      sizeof(fd_txn_t)                    =  22
     108             :      64 × sizeof(fd_txn_instr_t)         = 640 +
     109             :      24 × sizeof(fd_txn_acct_addr_lut_t) = 192 +
     110             :                                          = 854
     111             : 
     112             :    Worst-case V1 transaction: 64 empty instructions, no ALTs as
     113             :    ALTs are not allowed in V1 transactions:
     114             :      sizeof(fd_txn_t)                    =  22
     115             :      64 × sizeof(fd_txn_instr_t)         = 640 +
     116             :                                          = 662
     117             : 
     118             :    So the worst-case parsed transaction size is the V0 transaction
     119             :    case. */
     120          21 : #define FD_TXN_MAX_SZ                (854UL)
     121             : 
     122             : 
     123             : /* FD_TXN_MTU: The maximum size (in bytes, inclusive) of a serialized
     124             :    transaction, across all transaction version formats. */
     125       18774 : #define FD_TXN_MTU                  (4096UL)
     126             : 
     127             : /* FD_TXN_MTU_V0: The maximum size (in bytes, inclusive) of a serialized
     128             :    legacy or V0 transaction.
     129             : 
     130             :    Any transaction that has an MTU larger than this is required to
     131             :    use the transaction V1 format. */
     132    61340838 : #define FD_TXN_MTU_V0               (1232UL)
     133             : 
     134             : /* FD_TXN_MIN_SERIALIZED_SZ: The minimum size (in bytes) of a serialized
     135             :    transaction, using fd_txn_parse() verification rules.
     136             : 
     137             :    Minimum legacy transaction size: 134
     138             :    Minimum v0 transaction size:     136
     139             :    Minimum v1 transaction size:     138 */
     140        6639 : #define FD_TXN_MIN_SERIALIZED_SZ     (134UL)
     141             : 
     142             : /* BEGIN Agave limits */
     143             : 
     144             : /* Maximum number of accounts that a transaction may lock. */
     145      252597 : #define MAX_TX_ACCOUNT_LOCKS         (64UL)
     146             : 
     147             : /* In the FD runtime, we've sized things assuming up to
     148             :    MAX_TX_ACCOUNT_LOCKS accounts per transaction. We rely on the txn
     149             :    parser to enforce this limit, up till the point of
     150             :    validate_account_locks(). If the txn parser bumps the account limit,
     151             :    then we might overflow in the runtime. */
     152             : FD_STATIC_ASSERT( MAX_TX_ACCOUNT_LOCKS==FD_TXN_ACCT_ADDR_MAX, num_accounts_per_txn );
     153             : 
     154             : /* END Agave limits */
     155             : 
     156             : 
     157             : /* A Solana transaction instruction, i.e. one command or step to execute in a
     158             :    transaction.
     159             : 
     160             :    An instruction tells the runtime to execute one on-chain program (smart
     161             :    contract) with some arguments (think argc, argv).  The arguments come in the
     162             :    form of binary data and/or accounts, each of which is variable-sized and
     163             :    optional.
     164             : 
     165             :    Note that instructions specify accounts by giving an index into the
     166             :    transaction-level list of account addresses.  This means there are
     167             :    essentially two layers of indirection: a 1 B index to a 32 B address which
     168             :    specifies an account. */
     169             : struct fd_txn_instr {
     170             :   /* program_id: The on-chain program that this instruction invokes,
     171             :      represented as the index of the program's account address in the
     172             :      containing transaction's list of account addresses. */
     173             :   uchar   program_id;
     174             :   uchar   _padding_reserved_1; /* explicitly declare what the compiler would
     175             :                                   insert anyways */
     176             : 
     177             :   /* acct_cnt: The number of accounts this instruction references.
     178             :      N.B. It is possible to pass > 256 accounts to an instruction, but not more
     179             :      than 256 unique accounts. */
     180             :   ushort  acct_cnt;
     181             : 
     182             :   /* data_sz: The size (in bytes) of the data passed to this instruction. The
     183             :      data itself is included in the transaction, so is limited to the overall
     184             :      transaction size. */
     185             :   ushort  data_sz;
     186             : 
     187             :   /* acct_off: The offset (relative to the start of the transaction) in bytes
     188             :      where the account address index array starts.  This array has size
     189             :      acct_cnt.
     190             : 
     191             :      Specifically, if uchar const * payload is a pointer to the first byte of
     192             :      the transaction data in the packet, then the array (payload+acct_off)[i]
     193             :      for i in [0, acct_cnt) gives all of the accounts passed to this
     194             :      instruction.  As with the program_id, these accounts are represented as
     195             :      indices into the transaction's list of account addresses.
     196             :      */
     197             :   ushort  acct_off;
     198             : 
     199             :   /* data_off: The offset (relative to the start of the transaction) in bytes
     200             :      where the instruction data array starts.  This array has size data_sz.
     201             : 
     202             :      Specifically, if uchar const * payload is a pointer to the first byte of
     203             :      the transaction data in the packet, then the array (payload+data_off)[i]
     204             :      for i in [0, data_sz) gives the binary data passed to this instruction. */
     205             :   ushort  data_off;
     206             : };
     207             : 
     208             : typedef struct fd_txn_instr fd_txn_instr_t;
     209             : 
     210             : 
     211             : /* fd_txn_t: A Solana transaction. As explained above, a transaction is mostly
     212             :    a list of instructions, but there are a few other major components:
     213             :    - a list of account addresses,
     214             :    - the hash of a recent block (used as a nonce and TTL), and
     215             :    - potentially (if it's a V2 transaction) some address lookup tables. */
     216             : struct fd_txn {
     217             :   /* transaction_version: The version number of this transaction. Currently
     218             :      must be one of { FD_TXN_VLEGACY, FD_TXN_V0, FD_TXN_V1 }. */
     219             :   uchar       transaction_version;
     220             : 
     221             :   /* signature_cnt: The number of signatures in this transaction. signature_cnt
     222             :      in [1, FD_TXN_SIG_MAX]. */
     223             :   uchar       signature_cnt;
     224             : 
     225             :   /* signature_off: The offset (relative to the start of the transaction) in
     226             :      bytes where the signatures start.
     227             : 
     228             :      Specifically, if uchar const * payload is a pointer to the first byte of
     229             :      the transaction data in the packet, then signature i starts at
     230             :      (payload+signature_off)[ FD_TXN_SIGNATURE_SZ*i ] for i in
     231             :      [0, signature_cnt). */
     232             : 
     233             :   ushort      signature_off;
     234             : 
     235             :   /* message_off: The offset (relative to the start of the transaction)
     236             :      in bytes where the 'message' starts.
     237             : 
     238             :      The message is the part of the transaction covered by the
     239             :      signatures.
     240             : 
     241             :      For legacy/V0 transactions, the signatures are at the front of the
     242             :      packet and the message is at the end, so the message spans from
     243             :      message_off to the end of the packet.
     244             : 
     245             :      For V1 transactions, the message is at the front of the packet and
     246             :      the signatures are at the end, so the message spans from
     247             :      message_off to signature_off.
     248             : 
     249             :      Use fd_txn_msg_sz( txn, payload_sz ) to determine the length of
     250             :      the message. */
     251             :   ushort      message_off;
     252             : 
     253             :   /* readonly_signed_cnt: Of the signature_cnt signatures, readonly_signed_cnt
     254             :      of them are read only. Since there must be a fee payer,
     255             :      readonly_signed_cnt in [0, signature_cnt) */
     256             :   uchar       readonly_signed_cnt;
     257             : 
     258             :   /* readonly_unsigned_cnt: Of the account addresses that don't have an
     259             :      accompanying signature, readonly_unsigned_cnt of them are read only.
     260             :      readonly_unsigned_cnt in [0, acct_addr_cnt-signature_cnt].  Excludes any
     261             :      accounts from address table lookups. */
     262             :   uchar       readonly_unsigned_cnt;
     263             : 
     264             :   /* acct_addr_cnt: The number of account addresses in this transaction.
     265             :      acct_addr_cnt in [1, FD_TXN_ACCT_ADDR_MAX].  Excludes any accounts from
     266             :      address table lookups. */
     267             :   ushort      acct_addr_cnt;
     268             : 
     269             :   /* acct_addr_off: The offset (relative to the start of the transaction) in
     270             :      bytes where the account addresses start.
     271             : 
     272             :      Specifically, if uchar const * payload is a pointer to the first byte of
     273             :      the transaction data in the packet, then the array
     274             :      (payload+acct_addr_off)[ FD_TXN_ACCT_ADDR_SZ*i ] for i in [0, account_cnt)
     275             :      gives all of the account addresses in this transaction.  Since
     276             :      (payload+acct_addr_off) points inside the packet, it should be treated as
     277             :      pointing to unaligned data.
     278             : 
     279             :      The order of these addresses is important, because it determines the
     280             :      "permission flags" for the account in this transaction.
     281             :      Accounts ordered:
     282             :                                           Index Range                                 |   Signer?    |  Writeable?
     283             :      ---------------------------------------------------------------------------------|--------------|-------------
     284             :       [0,                                     signature_cnt - readonly_signed_cnt)    |  signer      |   writable
     285             :       [signature_cnt - readonly_signed_cnt,   signature_cnt)                          |  signer      |   readonly
     286             :       [signature_cnt,                         acct_addr_cnt - readonly_unsigned_cnt)  |  not signer  |   writable
     287             :       [acct_addr_cnt - readonly_unsigned_cnt, acct_addr_cnt)                          |  not signer  |   readonly
     288             :      */
     289             :   ushort      acct_addr_off;
     290             : 
     291             :   /* recent_blockhash_off: The offset (relative to the start of the
     292             :      transaction) in bytes where the recent blockhash starts.
     293             : 
     294             :      Specifically, if uchar const * payload is a pointer to the first byte of
     295             :      the transaction data in the packet, then (payload+recent_blockhash_off) is
     296             :      a pointer to the blockhash. Since the resulting pointer points inside the
     297             :      packet, it should be treated as pointing to unaligned data. In practice,
     298             :      recent_blockhash_off is 5 or 6 (mod 32). */
     299             :   ushort      recent_blockhash_off;
     300             : 
     301             :   /* addr_table_lookup_cnt: The number of address lookup tables this
     302             :      transaction contains.  Must be 0 if transaction_version==FD_TXN_VLEGACY.
     303             :      addr_table_lookup_cnt in [0, FD_TXN_ADDR_TABLE_LOOKUP_MAX]. */
     304             :   uchar       addr_table_lookup_cnt;
     305             : 
     306             :   /* addr_table_adtl_writable_cnt: The total number of writable account
     307             :      addresses across all of the address table lookups.
     308             :      addr_table_adtl_writable_cnt in [0, addr_table_adtl_cnt]. */
     309             :   uchar       addr_table_adtl_writable_cnt;
     310             : 
     311             :   /* addr_table_adtl_cnt: The total number of account addresses summed across
     312             :      all the address lookup tables. addr_table_adtl_cnt in
     313             :      [0, FD_TXN_ACCT_ADDR_MAX - acct_addr_cnt]. Since acct_addr_cnt > 0,
     314             :      addr_table_adtl_cnt < 64. */
     315             :   uchar      addr_table_adtl_cnt;
     316             : 
     317             :   uchar      _padding_reserved_1; /* explicit padding the compiler would have
     318             :                                      inserted anyways */
     319             : 
     320             :   /* v1_txn_config_values_off: The offset relative to the start of the
     321             :      transaction of the config values region.  The config values region
     322             :      contains the fields which the V1 config mask indicates are
     323             :      present, packed together.  Fields which are not present are not
     324             :      included, not set to zero.
     325             : 
     326             :      Legacy/V0 transactions have no config mask, so this field is 0
     327             :      for legacy/v0 transactions. */
     328             :   ushort     v1_txn_config_values_off;
     329             : 
     330             :   /* From the address table lookups, we can add the following to the above table
     331             :                                                 Index Range                                         |   Signer?    |  Writeable?
     332             :      -----------------------------------------------------------------------------------------------|--------------|-------------
     333             :      ...
     334             :       [acct_addr_cnt,                                acct_addr_cnt + addr_table_adtl_writable_cnt)  |  not signer  |   writable
     335             :       [acct_addr_cnt + addr_table_adtl_writable_cnt, acct_addr_cnt + addr_table_adtl_cnt)           |  not signer  |   readonly
     336             :       */
     337             : 
     338             :   /* instr_cnt: The number of instructions in this transaction.
     339             :      instr_cnt in [0, FD_TXN_INSTR_MAX]. */
     340             :   ushort      instr_cnt;
     341             : 
     342             :   /* instr: The array of instructions in this transaction. It's a "flexible array
     343             :      member" since C does not allow the pretty typical 0-len array at the end
     344             :      of the struct trick.
     345             :      Indexed [0, instr_cnt). */
     346             :   fd_txn_instr_t instr[ ];
     347             : 
     348             :   /* Logically, there's another field here:
     349             :      address_tables: The address tables this transaction imports and which
     350             :      accounts from them are selected for inclusion in this transaction's
     351             :      overall list of accounts. Indexed [0, addr_table_lookup_cnt).
     352             :   fd_txn_acct_addr_lut_t address_tables[ ];
     353             :      To access it, call fd_txn_get_address_tables( ). */
     354             : 
     355             : };
     356             : 
     357             : typedef struct fd_txn fd_txn_t;
     358             : 
     359             : /* fd_txn_acct_addr_lut: An on-chain address lookup table. Solana added this to
     360             :    the Transaction v2 spec in order to allow a transaction to reference more
     361             :    accounts. This struct specifies which account addresses from an on-chain
     362             :    list should be selected to include in the list of account addresses
     363             :    available to instructions in this transaction */
     364             : struct fd_txn_acct_addr_lut {
     365             :   /* addr_off: The offset (relative to the start of the transaction) in bytes
     366             :      where the address of the account containing the list of to load is stored.
     367             : 
     368             :      Specifically, if uchar const * payload is a pointer to the first byte of
     369             :      the transaction data in the packet, then
     370             :      (fd_txn_acct_addr_t*)(payload+addr_off) is a pointer to the account
     371             :      address.  Since (payload+acct_addr_off) points inside the packet, it
     372             :      should be treated as pointing to unaligned data. */
     373             :   ushort addr_off;
     374             : 
     375             :   /* writable_cnt: The number of account addresses this LUT selects as writable
     376             :      from the on-chain list. */
     377             :   uchar  writable_cnt;
     378             :   /* readonly_cnt: The number of account addresses this LUT selects as read
     379             :      only from the on-chain list. */
     380             :   uchar  readonly_cnt;
     381             : 
     382             :   /* writable_off: The offset (relative to the start of the transaction) in
     383             :      bytes where the writable account indices begins.
     384             : 
     385             :      Specifically, if uchar const * payload is a pointer to the first byte of
     386             :      the transaction data in the packet, then (payload+writable_off)[i] for i
     387             :      in [0, writable_cnt) gives the indices into the on-chain list that are
     388             :      selected for inclusion in this transaction's list of account addresses as
     389             :      writable accounts. */
     390             :   ushort writable_off;
     391             : 
     392             :   /* readonly_off: The offset (relative to the start of the transaction) in
     393             :      bytes where the read only account indices begins.
     394             : 
     395             :      Specifically, if uchar const * payload is a pointer to the first byte of
     396             :      the transaction data in the packet, then (payload+readonly_off)[i] for i
     397             :      in [0, readonly_cnt) gives the indices into the on-chain list that are
     398             :      selected for inclusion in this transaction's list of account addresses as
     399             :      read only accounts. */
     400             :   ushort readonly_off;
     401             : };
     402             : 
     403             : typedef struct fd_txn_acct_addr_lut fd_txn_acct_addr_lut_t;
     404             : 
     405       87825 : #define FD_TXN_PARSE_COUNTERS_RING_SZ (32UL)
     406             : 
     407             : /* Counters for collecting some metrics about the outcome of parsing
     408             :    transactions */
     409             : struct fd_txn_parse_counters {
     410             :   /* success_cnt: the number of times a transaction parsed successfully */
     411             :   ulong success_cnt;
     412             :   /* failure_cnt: the number of times a transaction was ill-formed and failed
     413             :      to parse for any reason */
     414             :   ulong failure_cnt;
     415             :   /* failure_ring: some information about the causes of recent transaction
     416             :      parsing failures.  Specifically, the line of code which detected that the
     417             :      ith malformed transaction was malformed maps to
     418             :      failure_ring[ i%FD_TXN_PARSE_COUNTERS_RING_SZ ] (where i starts at 0), and the
     419             :      last instance mapping to each element of the array is the one that is
     420             :      actually present.  If fewer than FD_TXN_PARSE_COUNTERS_RING_SZ failures have
     421             :      occurred, the contents of some entries in this array are undefined. */
     422             :   ulong failure_ring[ FD_TXN_PARSE_COUNTERS_RING_SZ ];
     423             : };
     424             : typedef struct fd_txn_parse_counters fd_txn_parse_counters_t;
     425             : 
     426             : FD_PROTOTYPES_BEGIN
     427             : /* fd_txn_get_address_tables: Returns the array of address tables in this
     428             :    transaction.  This depends on the value of txn->instr_cnt being correct.  The
     429             :    lifetime of the returned pointer is the same as the fd_txn_t pointer passed
     430             :    as an argument, so it's not necessary to free the returned pointer
     431             :    separately.  Treat it as if this function returned a pointer to a member of
     432             :    the struct.  Suppose x=fd_txn_get_address_tables( txn ), then x[ i ] is valid
     433             :    for i in [0, txn->addr_table_lookup_cnt ). */
     434             : static inline fd_txn_acct_addr_lut_t *
     435    61282257 : fd_txn_get_address_tables( fd_txn_t * txn ) {
     436    61282257 :   return (fd_txn_acct_addr_lut_t *)(txn->instr + txn->instr_cnt);
     437    61282257 : }
     438             : 
     439             : static inline fd_txn_acct_addr_lut_t const *
     440         474 : fd_txn_get_address_tables_const( fd_txn_t const * txn ) {
     441         474 :   return (fd_txn_acct_addr_lut_t const *)(txn->instr + txn->instr_cnt);
     442         474 : }
     443             : 
     444             : /* fd_acct_addr_t: An Solana account address, which may be an Ed25519
     445             :    public key, a SHA256 hash from a program derived address, a hardcoded
     446             :    sysvar, etc.  This type does not imply any alignment. */
     447             : union fd_acct_addr {
     448             :   uchar b[FD_TXN_ACCT_ADDR_SZ];
     449             : };
     450             : typedef union fd_acct_addr fd_acct_addr_t;
     451             : 
     452             : /* fd_txn_get_{signatures, acct_addrs}: Returns the array of Ed25519
     453             :    signatures or account addresses (commonly, yet imprecisely called
     454             :    pubkeys), respectively, in `payload`, the serialization of the
     455             :    transaction described by `txn`.  The number of signatures is seen in
     456             :    `txn->signature_cnt` and the number of account addresses is in
     457             :    `txn->acct_addr_cnt`.
     458             : 
     459             :    The lifetime of the returned signature is the lifetime of `payload`.
     460             :    Expect the returned pointer to point to memory with no particular
     461             :    alignment.  U.B. If `payload` and `txn` were not arguments to a valid
     462             :    `fd_txn_parse` call or if either was modified after the parse call.
     463             :    */
     464             : FD_FN_PURE static inline fd_ed25519_sig_t const *
     465             : fd_txn_get_signatures( fd_txn_t const * txn,
     466         153 :                        void     const * payload ) {
     467         153 :    return (fd_ed25519_sig_t const *)((ulong)payload + (ulong)txn->signature_off);
     468         153 : }
     469             : 
     470             : FD_FN_PURE static inline fd_acct_addr_t const *
     471             : fd_txn_get_acct_addrs( fd_txn_t const * txn,
     472      856877 :                        void     const * payload ) {
     473      856877 :   return (fd_acct_addr_t const *)((ulong)payload + (ulong)txn->acct_addr_off);
     474      856877 : }
     475             : 
     476             : FD_FN_PURE static inline uchar const *
     477             : fd_txn_get_recent_blockhash( fd_txn_t const * txn,
     478        3382 :                              void     const * payload ) {
     479        3382 :   return (uchar const *)((ulong)payload + (ulong)txn->recent_blockhash_off);
     480        3382 : }
     481             : 
     482             : FD_FN_PURE static inline uchar const *
     483             : fd_txn_get_instr_accts( fd_txn_instr_t const * instr,
     484          15 :                         void           const * payload ) {
     485          15 :   return (uchar const *)((ulong)payload + (ulong)instr->acct_off);
     486          15 : }
     487             : 
     488             : FD_FN_PURE static inline uchar const *
     489             : fd_txn_get_instr_data( fd_txn_instr_t const * instr,
     490         705 :                        void           const * payload ) {
     491         705 :   return (uchar const *)((ulong)payload + (ulong)instr->data_off);
     492         705 : }
     493             : 
     494             : /* fd_txn_is_simple_vote_transaction: Returns 1 if `txn` is a simple
     495             :    vote and 0 otherwise.  `txn` is a non-null pointer to a Solana
     496             :    transaction parsed by fd_txn_parse_core.  `payload` is a non-null
     497             :    pointer to serialization of `txn`, which is coupled with `txn` as
     498             :    both `txn` and `payload` are different representations of the same
     499             :    data.
     500             : 
     501             :    A simple vote is a transaction that meets the following criteria:
     502             :    1. has 1 or 2 signatures
     503             :    2. is legacy transaction
     504             :    3. has exactly one instruction
     505             :    4. ...which must be a Vote instruction
     506             :  */
     507             : static inline int
     508             : fd_txn_is_simple_vote_transaction( fd_txn_t const * txn,
     509       68433 :                                    void     const * payload ) {
     510             :    /* base58 decode of Vote111111111111111111111111111111111111111 */
     511       68433 :    static const uchar vote_program_id[FD_TXN_ACCT_ADDR_SZ] = {
     512       68433 :       0x07U,0x61U,0x48U,0x1dU,0x35U,0x74U,0x74U,0xbbU,0x7cU,0x4dU,0x76U,0x24U,0xebU,0xd3U,0xbdU,0xb3U,
     513       68433 :       0xd8U,0x35U,0x5eU,0x73U,0xd1U,0x10U,0x43U,0xfcU,0x0dU,0xa3U,0x53U,0x80U,0x00U,0x00U,0x00U,0x00U };
     514             : 
     515       68433 :   fd_acct_addr_t const * addr_base = fd_txn_get_acct_addrs( txn, payload );
     516       68433 :   if( FD_UNLIKELY( txn->instr_cnt!=1UL ) )                      return 0;
     517        7176 :   if( FD_UNLIKELY( txn->transaction_version!=FD_TXN_VLEGACY ) ) return 0;
     518        7161 :   if( FD_UNLIKELY( txn->signature_cnt>2UL ) )                   return 0;
     519        7137 :   ulong prog_id_idx = (ulong)txn->instr[0].program_id;
     520        7137 :   fd_acct_addr_t const * prog_id = addr_base + prog_id_idx;
     521        7137 :   return fd_memeq( prog_id->b, vote_program_id, FD_TXN_ACCT_ADDR_SZ );
     522        7161 : }
     523             : 
     524             : /* fd_txn_align returns the alignment in bytes required of a region of
     525             :    memory to be used as a fd_txn_t.  It is the same as
     526             :    alignof(fd_txn_t). */
     527             : static inline ulong
     528           0 : fd_txn_align( void ) {
     529           0 :   return alignof(fd_txn_t);
     530           0 : }
     531             : 
     532             : /* fd_txn_footprint: Returns the total size of txn, including the
     533             :    instructions and the address tables (if any). */
     534             : static inline ulong
     535             : fd_txn_footprint( ulong instr_cnt,
     536    61265664 :                   ulong addr_table_lookup_cnt ) {
     537    61265664 :   return sizeof(fd_txn_t) + instr_cnt*sizeof(fd_txn_instr_t) + addr_table_lookup_cnt*sizeof(fd_txn_acct_addr_lut_t);
     538    61265664 : }
     539             : 
     540             : 
     541             : /* Each account address in a transaction has 3 independent binary
     542             :    properties:
     543             :    -  readonly/writable: this is enforced in the runtime, but a
     544             :        transaction fails if it tries to modify the contents of an
     545             :        account it marks as readonly
     546             :    -  signer/nonsigner: the sigverify tile ensures that the transaction
     547             :        has been validly signed by the key associated to each account
     548             :        address marked as a signer
     549             :    -  immediate/address lookup table: account addresses can come from
     550             :        the transaction itself ("immediate"), which is the only option
     551             :        for legacy transactions, or from an address lookup table
     552             : 
     553             :    For example, the fee payer must be writable, a signer, and immediate.
     554             : 
     555             :    From these properties, we can make categories of account addresses
     556             :    for counting and iterating over account addresses.  Since these
     557             :    properties can be set independently, it would seem to give us 2*2*2=8
     558             :    categories of accounts based on the properties, but account addresses
     559             :    that come from an address lookup table cannot be signers, giving 6
     560             :    raw categories instead of 8.
     561             : 
     562             :    The individual types of accounts are defined as bitflags so that
     563             :    combination categories can be created easily, e.g. all readonly
     564             :    accounts or all signers. */
     565             : 
     566             : /*                                                        Signer?   Writable?   Source? */
     567     8696346 : #define FD_TXN_ACCT_CAT_WRITABLE_SIGNER         0x01  /*    Yes        Yes        imm   */
     568     8143074 : #define FD_TXN_ACCT_CAT_READONLY_SIGNER         0x02  /*    Yes        No         imm   */
     569     8726484 : #define FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM  0x04  /*    No         Yes        imm   */
     570     8173386 : #define FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM  0x08  /*    No         No         imm   */
     571     8696187 : #define FD_TXN_ACCT_CAT_WRITABLE_ALT            0x10  /*    No         Yes       lookup */
     572     8143041 : #define FD_TXN_ACCT_CAT_READONLY_ALT            0x20  /*    No         No        lookup */
     573             : 
     574             : /* Define some groupings for convenience.  In the
     575             :    table below, "Any" means "don't care" */
     576      243522 : #define FD_TXN_ACCT_CAT_WRITABLE                0x15  /*   Any         Yes        Any   */
     577      135615 : #define FD_TXN_ACCT_CAT_READONLY                0x2A  /*   Any         No         Any   */
     578     1175487 : #define FD_TXN_ACCT_CAT_SIGNER                  0x03  /*   Yes         Any       Any/imm*/
     579         384 : #define FD_TXN_ACCT_CAT_NONSIGNER               0x3C  /*   No          Any        Any   */
     580      173273 : #define FD_TXN_ACCT_CAT_IMM                     0x0F  /*   Any         Any        imm   */
     581       38178 : #define FD_TXN_ACCT_CAT_ALT                     0x30  /*   No          Any       lookup */
     582         489 : #define FD_TXN_ACCT_CAT_NONE                    0x00  /*      --- Empty set ---         */
     583       42927 : #define FD_TXN_ACCT_CAT_ALL                     0x3F  /*   Any         Any        Any   */
     584             : 
     585             : /* fd_txn_account_cnt: Returns the number of accounts referenced by this
     586             :    transaction that have the property specified by include_category.
     587             :    txn must be a pointer to a valid transaction.  include_cat must be
     588             :    one of the previously defined FD_TXN_ACCT_CAT_* values.  Ideally,
     589             :    include_cat should be a compile-time constant, in which case this
     590             :    function typically compiles to about 3 instructions. */
     591             : static inline ulong
     592             : fd_txn_account_cnt( fd_txn_t const * txn,
     593     7589511 :                     int              include_cat ) {
     594     7589511 :   ulong cnt = 0UL;
     595     7589511 :   if( include_cat & FD_TXN_ACCT_CAT_WRITABLE_SIGNER        ) cnt += (ulong)txn->signature_cnt - (ulong)txn->readonly_signed_cnt;
     596     7589511 :   if( include_cat & FD_TXN_ACCT_CAT_READONLY_SIGNER        ) cnt += (ulong)txn->readonly_signed_cnt;
     597     7589511 :   if( include_cat & FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM ) cnt += (ulong)txn->readonly_unsigned_cnt;
     598     7589511 :   if( include_cat & FD_TXN_ACCT_CAT_WRITABLE_ALT           ) cnt += (ulong)txn->addr_table_adtl_writable_cnt;
     599     7589511 :   if( include_cat & FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM )
     600     3054993 :     cnt += (ulong)txn->acct_addr_cnt - (ulong)txn->signature_cnt - (ulong)txn->readonly_unsigned_cnt;
     601     7589511 :   if( include_cat & FD_TXN_ACCT_CAT_READONLY_ALT           )
     602      630666 :     cnt += (ulong)txn->addr_table_adtl_cnt - (ulong)txn->addr_table_adtl_writable_cnt;
     603             : 
     604     7589511 :   return cnt;
     605     7589511 : }
     606             : 
     607             : /* fd_txn_acct_iter_{init, next, end, idx}: These functions are used for
     608             :    iterating over the accounts in a transaction that have the property
     609             :    specified by include_cat.
     610             : 
     611             :    Example usage:
     612             : 
     613             :    fd_txn_acct_addr_t const * acct = fd_txn_get_acct_addrs( txn, payload );
     614             :    for( fd_txn_acct_iter_t i=fd_txn_acct_iter_init( txn, FD_TXN_ACCT_CAT_WRITABLE );
     615             :          i!=fd_txn_acct_iter_end(); i=fd_txn_acct_iter_next( i ) ) {
     616             :      // Do something with acct[ fd_txn_acct_iter_idx( i ) ]
     617             :    }
     618             : 
     619             :    For fd_txn_acct_iter_init, txn must be a pointer to a valid
     620             :    transaction and include_cat must be one of the FD_TXN_ACCT_CAT_*
     621             :    values defined above (or a bitwise combination of them).  On
     622             :    completion, returns a value i such that fd_txn_acct_iter_idx( i ) is
     623             :    the index of the first account address meeting the specified
     624             :    criteria, or i==fd_txn_acct_iter_end() if there aren't any account
     625             :    addresses that meet the criteria.
     626             : 
     627             :    For fd_acct_iter_next, cur should be the current value of the
     628             :    iteration variable.  Advances the iteration variable such that
     629             :    fd_txn_acct_iter_idx( i ) is the index of the next account meeting
     630             :    the initially specified criteria, or i==fd_txn_acct_iter_end() if
     631             :    there aren't any more account addresses meeting the criteria.  It is
     632             :    undefined behavior to call fd_acct_iter_next with a value of cur not
     633             :    returned by a call to either fd_acct_iter_init or fd_acct_iter_next.
     634             :    It's also U.B. to call fd_acct_iter_next after fd_acct_iter_end has
     635             :    been returned.
     636             : 
     637             :    fd_txn_acct_iter_t should be treated as an opaque handle and not
     638             :    modified other than by using fd_txn_acc_iter_next.  You can peek and
     639             :    see that it's a ulong, so it fits in a register and doesn't need to
     640             :    be destroyed or cleaned up.  It's safe to save a fd_txn_acct_iter_t
     641             :    value to resume iteration later with the same transaction. */
     642             : 
     643             : typedef ulong fd_txn_acct_iter_t;
     644             : 
     645             : /* Account addresses are categorized into 6 categories, and all the
     646             :    account addresses for each category are stored contiguously.  This
     647             :    means that for any subset of the 6 categories that the user wants to
     648             :    iterate over, there are at most 3 disjoint ranges.
     649             : 
     650             :    For any iteration space I, we can choose 6 integers
     651             :    {start,count}_{0,1,2} so that
     652             :     I = [start0, start0+count0) U [start1, start1+count1)
     653             :                                 U [start2, start2+count2)
     654             :    Any empty intervals are represented as [0, 0).
     655             :    We store the control word as a single ulong with start0 in the low
     656             :    order bits.  Then the current account index can be retrieved by
     657             :    taking the low order byte, and the count remaining in the current
     658             :    interval is the second lowest byte.  We can update both in one
     659             :    instruction by subtracting 255. */
     660             : 
     661             : static inline fd_txn_acct_iter_t FD_FN_PURE
     662             : fd_txn_acct_iter_init( fd_txn_t const * txn,
     663      380409 :                        int              include_cat ) {
     664             :   /* Our goal is to output something that looks like [start0, count0,
     665             :      start1, count1, start2, count2, 0, 0] from lowest order to highest.
     666             :      We construct the potentially 3 (start, count) pairs and then
     667             :      branchlessly get rid of any empty ones. */
     668      380409 :   ulong control[3] = { 0 }; /* High 6 bytes of each stay element not touched */
     669      380409 :   ulong i = (ulong)(-1L);   /* So that it is 0 post increment */
     670             : 
     671             :   /* Make references more convenient.  Dead code elimination seems to
     672             :      take care of the unneeded ones. */
     673      380409 :   ulong s = txn->signature_cnt;
     674      380409 :   ulong q = txn->readonly_signed_cnt;
     675      380409 :   ulong r = txn->readonly_unsigned_cnt;
     676      380409 :   ulong a = txn->acct_addr_cnt;
     677      380409 :   ulong t = txn->addr_table_adtl_cnt;
     678      380409 :   ulong u = txn->addr_table_adtl_writable_cnt;
     679             : 
     680             :   /* All the branches here should be known at compile time. */
     681             :   /* If WRITABLE_SIGNER is included, then f>>1 is 0, so the second
     682             :      branch will always be true, setting control[0]=0. */
     683      380409 : # define INCLUDE_RANGE(f, start, cnt)                        \
     684     2282454 :   if( include_cat & (f) ) {                                  \
     685     1248849 :     if( !(include_cat & ((f)>>1) ) ) control[ ++i ]=(start); \
     686     1248849 :     control[ i ] += (cnt)<<8;                                \
     687     1248849 :   }
     688             : 
     689      380409 :   INCLUDE_RANGE( FD_TXN_ACCT_CAT_WRITABLE_SIGNER,          0, s-q   );
     690      380409 :   INCLUDE_RANGE( FD_TXN_ACCT_CAT_READONLY_SIGNER,        s-q, q     );
     691      380409 :   INCLUDE_RANGE( FD_TXN_ACCT_CAT_WRITABLE_NONSIGNER_IMM,   s, a-r-s );
     692      380409 :   INCLUDE_RANGE( FD_TXN_ACCT_CAT_READONLY_NONSIGNER_IMM, a-r, r     );
     693      380409 :   INCLUDE_RANGE( FD_TXN_ACCT_CAT_WRITABLE_ALT,             a, u     );
     694      380409 :   INCLUDE_RANGE( FD_TXN_ACCT_CAT_READONLY_ALT,           a+u, t-u   );
     695      380409 : # undef INCLUDE_RANGE
     696             : 
     697             :   /* We now need to delete the empty intervals (if any). */
     698      380409 :   ulong control0 = control[0];
     699      380409 :   ulong control1 = control[1];
     700      380409 :   ulong control2 = control[2];
     701             : 
     702      380409 :   int control2_empty = !(control2&0xFF00UL);
     703      380409 :   control2 = fd_ulong_if( control2_empty, 0UL,      control2 );
     704             : 
     705      380409 :   int control1_empty = !(control1&0xFF00UL);
     706      380409 :   control1 = fd_ulong_if( control1_empty, control2, control1 );
     707      380409 :   control2 = fd_ulong_if( control1_empty, 0UL,      control2 );
     708             : 
     709      380409 :   int control0_empty = !(control0&0xFF00UL);
     710      380409 :   control0 = fd_ulong_if( control0_empty, control1, control0 );
     711      380409 :   control1 = fd_ulong_if( control0_empty, control2, control1 );
     712      380409 :   control2 = fd_ulong_if( control0_empty, 0UL,      control2 );
     713             : 
     714      380409 :   return control0 | (control1<<16) | (control2<<32);
     715      380409 : }
     716             : 
     717             : static inline fd_txn_acct_iter_t FD_FN_CONST
     718     1419213 : fd_txn_acct_iter_next( fd_txn_acct_iter_t cur ) {
     719     1419213 :   cur = cur + 0x0001UL - 0x0100UL; /* Increment low byte, decrement count */
     720             :   /* Move to the next interval if we're done with this one. */
     721     1419213 :   return fd_ulong_if( cur&0xFF00UL, cur, cur>>16 );
     722     1419213 : }
     723             : 
     724     1799622 : static inline fd_txn_acct_iter_t FD_FN_CONST fd_txn_acct_iter_end( void                   ) { return 0UL;          }
     725     1925532 : static inline ulong              FD_FN_CONST fd_txn_acct_iter_idx( fd_txn_acct_iter_t cur ) { return cur & 0xFFUL; }
     726             : 
     727             : /* fd_txn_parse_core: Parses a transaction from the canonical encoding, i.e.
     728             :    the format used on the wire.
     729             : 
     730             :    Payload points to the first byte of encoded transaction, e.g. the
     731             :    first byte of the UDP/Quic payload if the transaction comes from the
     732             :    network.  The encoded transaction must occupy exactly [payload,
     733             :    payload+payload_sz), i.e. this method will read no more than
     734             :    payload_sz bytes from payload, but it will reject the transaction if
     735             :    it contains extra padding at the end or continues past
     736             :    payload+payload_sz.
     737             : 
     738             :    out_buf is the memory where the parsed transaction will be stored.
     739             :    out_buf must be non-NULL and have room for at least FD_TXN_MAX_SZ
     740             :    bytes.
     741             : 
     742             :    Returns the total size of the resulting fd_txn struct on success and
     743             :    0 on failure.  On failure, the contents of out_buf are undefined,
     744             :    although nothing will be written beyond FD_TXN_MAX_SZ bytes.
     745             : 
     746             :    If counters_opt is non-NULL, some counters about the result of the
     747             :    parsing process will be accumulated into the struct pointed to by
     748             :    counters_opt.  Note: The returned txn object is not self-contained
     749             :    since it refers to byte ranges inside the payload.
     750             : 
     751             :    payload_sz_opt, if supplied, gets filled with the total bytes this txn
     752             :    uses (allowing for walking of an entry/microblock). If it is not supplied, the
     753             :    parse will return an error if the payload_sz does not exactly match. */
     754             : 
     755             : ulong
     756             : fd_txn_parse_core( uchar const             * payload,
     757             :                    ulong                     payload_sz,
     758             :                    void                    * out_buf,
     759             :                    fd_txn_parse_counters_t * counters_opt,
     760             :                    ulong *                   payload_sz_opt );
     761             : 
     762             : 
     763             : /* fd_txn_parse: Convenient wrapper around fd_txn_parse_core that eliminates some optional arguments */
     764             : static inline ulong
     765    61334061 : fd_txn_parse( uchar const * payload, ulong payload_sz, void * out_buf, fd_txn_parse_counters_t * counters_opt ) {
     766    61334061 :   return fd_txn_parse_core( payload, payload_sz, out_buf, counters_opt, NULL );
     767    61334061 : }
     768             : 
     769             : /* fd_txn_msg_sz returns the size in bytes of the signed message region
     770             :    of a transaction - not including the transaction signatures.
     771             : 
     772             :    The message bytes begin at message_off, relative to the start of
     773             :    the payload.
     774             : 
     775             :    Where these bytes are located in the transaction payload is
     776             :    dependent on the transaction format: legacy/V0 transactions have
     777             :    signatures at the front and then the message, whereas V1
     778             :    transactions have the message at the front and then the signatures.
     779             : 
     780             :    fd_txn_msg_sz and message_off should always be used together. */
     781             : FD_FN_PURE static inline ulong
     782             : fd_txn_msg_sz( fd_txn_t const * txn,
     783        6753 :                ulong            payload_sz ) {
     784        6753 :   ulong msg_end = ( txn->transaction_version==FD_TXN_V1 ) ? (ulong)txn->signature_off
     785        6753 :                                                           : payload_sz;
     786        6753 :   return msg_end - (ulong)txn->message_off;
     787        6753 : }
     788             : 
     789             : /* fd_txn_is_writable: Is the account at the supplied index writable
     790             : 
     791             :      Accounts ordered:
     792             :                                           Index Range                                 |   Signer?    |  Writeable?
     793             :      ---------------------------------------------------------------------------------|--------------|-------------
     794             :       [0,                                     signature_cnt - readonly_signed_cnt)    |  signer      |   writable
     795             :       [signature_cnt,                         acct_addr_cnt - readonly_unsigned_cnt)  |  not signer  |   writable
     796             : */
     797             : 
     798             : static inline int
     799        3114 : fd_txn_is_writable( fd_txn_t const * txn, ushort idx ) {
     800        3114 :   if (txn->transaction_version == FD_TXN_V0 && idx >= txn->acct_addr_cnt) {
     801         420 :     if (idx < (txn->acct_addr_cnt + txn->addr_table_adtl_writable_cnt)) {
     802           0 :       return 1;
     803           0 :     }
     804         420 :     return 0;
     805         420 :   }
     806             : 
     807        2694 :   if (idx < (txn->signature_cnt - txn->readonly_signed_cnt))
     808        1176 :     return 1;
     809        1518 :   if ((idx >= txn->signature_cnt) & (idx < (txn->acct_addr_cnt - txn->readonly_unsigned_cnt)))
     810         735 :     return 1;
     811             : 
     812         783 :   return 0;
     813        1518 : }
     814             : 
     815             : /* fd_txn_is_signer: Is the account at the supplied index a signer
     816             : 
     817             :      Accounts ordered:
     818             :                                           Index Range                                 |   Signer?    |  Writeable?
     819             :      ---------------------------------------------------------------------------------|--------------|-------------
     820             :       [0,                                     signature_cnt - readonly_signed_cnt)    |  signer      |   writable
     821             :       [signature_cnt - readonly_signed_cnt,   signature_cnt)                          |  signer      |   readonly
     822             : */
     823             : static inline int
     824        2028 : fd_txn_is_signer( fd_txn_t const * txn, int idx ) {
     825        2028 :   return idx < txn->signature_cnt;
     826        2028 : }
     827             : 
     828             : FD_PROTOTYPES_END
     829             : 
     830             : #endif /* HEADER_fd_src_ballet_txn_fd_txn_h */

Generated by: LCOV version 1.14