LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_runtime.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 10 0.0 %
Date: 2025-11-08 04:42:58 Functions: 0 0 -

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_runtime_fd_runtime_h
       2             : #define HEADER_fd_src_flamenco_runtime_fd_runtime_h
       3             : 
       4             : #include "stdarg.h"
       5             : 
       6             : #include "fd_runtime_err.h"
       7             : #include "fd_runtime_init.h"
       8             : #include "fd_rocksdb.h"
       9             : #include "fd_acc_mgr.h"
      10             : #include "fd_hashes.h"
      11             : #include "../features/fd_features.h"
      12             : #include "context/fd_capture_ctx.h"
      13             : #include "context/fd_exec_txn_ctx.h"
      14             : #include "info/fd_instr_info.h"
      15             : #include "../../disco/pack/fd_microblock.h"
      16             : #include "../../ballet/sbpf/fd_sbpf_loader.h"
      17             : #include "../vm/fd_vm_base.h"
      18             : 
      19             : #include "program/fd_bpf_loader_program.h"
      20             : 
      21             : /* Various constant values used by the runtime. */
      22             : 
      23           0 : #define MICRO_LAMPORTS_PER_LAMPORT (1000000UL)
      24             : 
      25           0 : #define DEFAULT_HASHES_PER_TICK  (12500)
      26             : #define UPDATED_HASHES_PER_TICK2 (17500)
      27             : #define UPDATED_HASHES_PER_TICK3 (27500)
      28             : #define UPDATED_HASHES_PER_TICK4 (47500)
      29             : #define UPDATED_HASHES_PER_TICK5 (57500)
      30             : #define UPDATED_HASHES_PER_TICK6 (62500)
      31             : 
      32             : #define FD_RUNTIME_TRACE_NONE   (0)
      33             : #define FD_RUNTIME_TRACE_SAVE   (1)
      34             : #define FD_RUNTIME_TRACE_REPLAY (2)
      35             : 
      36             : #define FD_RUNTIME_OFFLINE_NUM_ROOT_BLOCKS (6UL) /* 6 root blocks for offline replay */
      37             : 
      38             : #define FD_RENT_EXEMPT_RENT_EPOCH (ULONG_MAX)
      39             : 
      40           0 : #define SECONDS_PER_YEAR ((double)(365.242199 * 24.0 * 60.0 * 60.0))
      41             : 
      42             : /*
      43             :  * fd_block_entry_batch_t is a microblock/entry batch within a block.
      44             :  * The offset is relative to the start of the block's data region,
      45             :  * and indicates where the batch ends.  The (exclusive) end offset of
      46             :  * batch i is the (inclusive) start offset of batch i+1.  The 0th batch
      47             :  * always starts at offset 0.
      48             :  * On the wire, the presence of one of the COMPLETE flags in a data
      49             :  * shred marks the end of a batch.
      50             :  * In other words, batch ends are aligned with shred ends, and batch
      51             :  * starts are aligned with shred starts.  Usually a batch comprises
      52             :  * multiple shreds, and a block comprises multiple batches.
      53             :  * This information is useful because bincode deserialization needs to
      54             :  * be performed on a per-batch basis.  Precisely a single array of
      55             :  * microblocks/entries is expected to be deserialized from a batch.
      56             :  * Trailing bytes in each batch are ignored by default.
      57             :  */
      58             : struct fd_block_entry_batch {
      59             :   ulong end_off; /* exclusive */
      60             : };
      61             : typedef struct fd_block_entry_batch fd_block_entry_batch_t;
      62             : 
      63             : /* The below logic is used to size out the memory footprint generated by the
      64             :    runtime during transaction execution. */
      65             : 
      66             : /* The prevailing layout we have in the runtime is the meta followed by
      67             :    the account's data. This struct encodes that layout and asserts that
      68             :    the alignment requirements of the constituents are satisfied. */
      69             : // TODO: Use this struct at allocation sites so it's clear we use this layout
      70             : struct __attribute__((packed)) fd_account_rec {
      71             :   fd_account_meta_t meta;
      72             :   uchar data[] __attribute__((aligned(8)));
      73             : };
      74             : typedef struct fd_account_rec fd_account_rec_t;
      75           0 : #define FD_ACCOUNT_REC_ALIGN      (8UL)
      76             : #define FD_ACCOUNT_REC_DATA_ALIGN (8UL)
      77             : FD_STATIC_ASSERT( FD_ACCOUNT_REC_ALIGN>=alignof(fd_account_meta_t), account_rec_meta_align );
      78             : FD_STATIC_ASSERT( FD_ACCOUNT_REC_ALIGN>=FD_ACCOUNT_REC_DATA_ALIGN,  account_rec_data_align );
      79             : FD_STATIC_ASSERT( (offsetof(fd_account_rec_t, meta)%alignof(fd_account_meta_t))==0, account_rec_meta_offset );
      80             : FD_STATIC_ASSERT( (offsetof(fd_account_rec_t, data)%FD_ACCOUNT_REC_DATA_ALIGN )==0, account_rec_data_offset );
      81             : 
      82           0 : #define MAX_PERMITTED_DATA_INCREASE (10240UL) // 10KB
      83           0 : #define FD_BPF_ALIGN_OF_U128        (8UL    )
      84             : FD_STATIC_ASSERT( FD_BPF_ALIGN_OF_U128==FD_ACCOUNT_REC_DATA_ALIGN, input_data_align );
      85             : /* https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/ebpf.rs#L37-L38 */
      86             : #define FD_RUNTIME_EBPF_HOST_ALIGN (16UL)
      87             : 
      88             : /******** These macros bound out memory footprint ********/
      89             : 
      90             : /* The tight upper bound on borrowed account footprint over the
      91             :    execution of a single transaction. */
      92             : #define FD_RUNTIME_BORROWED_ACCOUNT_FOOTPRINT (MAX_TX_ACCOUNT_LOCKS * FD_ULONG_ALIGN_UP( FD_ACC_TOT_SZ_MAX, FD_ACCOUNT_REC_ALIGN ))
      93             : 
      94             : /* The bpf loader's serialization footprint is bounded in the worst case
      95             :    by 64 unique writable accounts which are each 10MiB in size (bounded
      96             :    by the amount of transaction accounts).  We can also have up to
      97             :    FD_INSTR_ACCT_MAX (256) referenced accounts in an instruction.
      98             : 
      99             :    - 8 bytes for the account count
     100             :    For each account:
     101             :      If duplicated:
     102             :        - 8 bytes for each duplicated account
     103             :     If not duplicated:
     104             :      - header for each unique account (96 bytes)
     105             :        - 1 account idx byte
     106             :        - 1 is_signer byte
     107             :        - 1 is_writable byte
     108             :        - 1 executable byte
     109             :        - 4 bytes for the original data length
     110             :        - 32 bytes for the key
     111             :        - 32 bytes for the owner
     112             :        - 8 bytes for the lamports
     113             :        - 8 bytes for the data length
     114             :        - 8 bytes for the rent epoch
     115             :      - 10MiB for the data (10485760 bytes)
     116             :      - 10240 bytes for resizing the data
     117             :      - 0 padding bytes because this is already 8 byte aligned
     118             :    - 8 bytes for instruction data length
     119             :    - 1232 bytes for the instruction data (TXN_MTU)
     120             :    - 32 bytes for the program id
     121             : 
     122             :   So the total footprint is:
     123             :   8 header bytes +
     124             :   192 duplicate accounts (256 instr accounts - 64 unique accounts) * 8 bytes     = 1536      duplicate account bytes +
     125             :   64 unique accounts * (96 header bytes + 10485760 bytes + 10240 resizing bytes) = 671750144 unique account bytes +
     126             :   8 + 1232 + 32                                                                  = 1272 bytes trailer bytes + program id = 671751416 bytes
     127             :   Total footprint: 671752960 bytes
     128             : 
     129             :   This is a reasonably tight-ish upper bound on the input region
     130             :   footprint for a single instruction at a single stack depth.  In
     131             :   reality the footprint would be slightly smaller because the
     132             :   instruction data can't be equal to the transaction MTU.
     133             :  */
     134             : #define FD_BPF_LOADER_UNIQUE_ACCOUNT_FOOTPRINT(direct_mapping)                                                                                              \
     135             :                                               (1UL                         /* dup byte          */                                                        + \
     136             :                                                sizeof(uchar)               /* is_signer         */                                                        + \
     137             :                                                sizeof(uchar)               /* is_writable       */                                                        + \
     138             :                                                sizeof(uchar)               /* executable        */                                                        + \
     139             :                                                sizeof(uint)                /* original_data_len */                                                        + \
     140             :                                                sizeof(fd_pubkey_t)         /* key               */                                                        + \
     141             :                                                sizeof(fd_pubkey_t)         /* owner             */                                                        + \
     142             :                                                sizeof(ulong)               /* lamports          */                                                        + \
     143             :                                                sizeof(ulong)               /* data len          */                                                        + \
     144             :                                                (direct_mapping ? FD_BPF_ALIGN_OF_U128 : FD_ULONG_ALIGN_UP( FD_RUNTIME_ACC_SZ_MAX, FD_BPF_ALIGN_OF_U128 )) + \
     145             :                                                MAX_PERMITTED_DATA_INCREASE                                                                                + \
     146             :                                                sizeof(ulong))              /* rent_epoch        */
     147             : #define FD_BPF_LOADER_DUPLICATE_ACCOUNT_FOOTPRINT (8UL) /* 1 dup byte + 7 bytes for padding */
     148             : 
     149             : #define FD_BPF_LOADER_INPUT_REGION_FOOTPRINT(account_lock_limit, direct_mapping)                                                                      \
     150             :                                               (FD_ULONG_ALIGN_UP( (sizeof(ulong)         /* acct_cnt       */                                       + \
     151             :                                                                    account_lock_limit*FD_BPF_LOADER_UNIQUE_ACCOUNT_FOOTPRINT(direct_mapping)        + \
     152             :                                                                    (FD_INSTR_ACCT_MAX-account_lock_limit)*FD_BPF_LOADER_DUPLICATE_ACCOUNT_FOOTPRINT + \
     153             :                                                                    sizeof(ulong)         /* instr data len */                                       + \
     154             :                                                                    FD_TXN_MTU            /* No instr data  */                                       + \
     155             :                                                                    sizeof(fd_pubkey_t)), /* program id     */                                          \
     156             :                                                                    FD_RUNTIME_EBPF_HOST_ALIGN ))
     157             : 
     158             : 
     159             : 
     160             : #define BPF_LOADER_SERIALIZATION_FOOTPRINT (671752960UL)
     161             : FD_STATIC_ASSERT( BPF_LOADER_SERIALIZATION_FOOTPRINT==FD_BPF_LOADER_INPUT_REGION_FOOTPRINT(64UL, 0), bpf_loader_serialization_footprint );
     162             : 
     163             : /* Bincode alloc footprint over the execution of a single transaction.
     164             :    As well as other footprint specific to each native program type.
     165             : 
     166             :    N.B. We know that bincode alloc footprint is bounded, because
     167             :    whenever we alloc something, we advance our pointer into the binary
     168             :    buffer, so eventually we are gonna reach the end of the buffer.
     169             :    This buffer is usually backed by and ultimately bounded in size by
     170             :    either accounts data or the transaction MTU.
     171             : 
     172             :    That being said, it's not obvious what the tight upper bound would
     173             :    be for allocations across all possible execution paths of all native
     174             :    programs, including possible CPIs from native programs.  The
     175             :    footprint estimate here is based on a manual review of our native
     176             :    program implementation.  Note that even if the possible paths remain
     177             :    steady at the Solana protocol level, the footprint is subject to
     178             :    change when we change our implementation.
     179             : 
     180             :    ### Native programs
     181             :    ALUT (migrated to BPF)
     182             :    Loader
     183             :      - rodata for bpf program relocation and validation
     184             :    Compute budget (0 allocations)
     185             :    Config (migrated to BPF)
     186             :    Precompile (0 allocations)
     187             :    Stake
     188             :      - The instruction with the largest footprint is deactivate_delinquent
     189             :        - During instruction decode, no allocations
     190             :        - During execution, this is (vote account get_state() + vote convert_to_current()) times 2, once for delinquent_vote_account, and once for reference_vote_account
     191             :    System
     192             :      - system_program_instruction_decode seed
     193             :    Vote
     194             :      - The instruction with the largest footprint is compact vote state update
     195             :        - During instruction decode, this is 9*lockouts_len bytes, MTU bounded
     196             :        - During execution, this is vote account get_state() + vote convert_to_current() + 12*lockouts_len bytes + lockouts_len ulong + deq_fd_landed_vote_t_alloc(lockouts_len)
     197             :    Zk Elgamal (0 allocations)
     198             : 
     199             :    The largest footprint is hence deactivate_delinquent, in which the
     200             :    two get_state() calls dominate the footprint.  In particular, the
     201             :    authorized_voters treaps bloat 40 bytes (epoch+pubkey) in a vote
     202             :    account to 72 bytes (sizeof(fd_vote_authorized_voter_t)) in memory.
     203             :  */
     204             : #define FD_RUNTIME_BINCODE_AND_NATIVE_FOOTPRINT (2UL*FD_RUNTIME_ACC_SZ_MAX*72UL/40UL)
     205             : 
     206             : /* Misc other footprint. */
     207             : #define FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT (FD_MAX_INSTRUCTION_STACK_DEPTH*FD_ULONG_ALIGN_UP(FD_SBPF_SYSCALLS_FOOTPRINT, FD_SBPF_SYSCALLS_ALIGN))
     208             : 
     209           0 : #define FD_RUNTIME_VM_TRACE_EVENT_MAX      (128UL<<20)
     210           0 : #define FD_RUNTIME_VM_TRACE_EVENT_DATA_MAX (2048UL)
     211             : #define FD_RUNTIME_VM_TRACE_FOOTPRINT      (FD_MAX_INSTRUCTION_STACK_DEPTH*fd_ulong_align_up( fd_vm_trace_footprint( FD_RUNTIME_VM_TRACE_EVENT_MAX, FD_RUNTIME_VM_TRACE_EVENT_DATA_MAX ), fd_vm_trace_align() ))
     212             : 
     213           0 : #define FD_RUNTIME_VM_TRACE_STATIC_FOOTPRINT (FD_RUNTIME_VM_TRACE_EVENT_MAX + sizeof(fd_vm_trace_t))
     214           0 : #define FD_RUNTIME_VM_TRACE_STATIC_ALIGN     (8UL)
     215             : 
     216             : #define FD_RUNTIME_MISC_FOOTPRINT (FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT)
     217             : #define FD_SOLFUZZ_MISC_FOOTPRINT (FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT + FD_RUNTIME_VM_TRACE_FOOTPRINT)
     218             : 
     219             : /* Now finally, we bound out the footprint of transaction execution. */
     220             : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(account_lock_limit, direct_mapping)                                         \
     221             :                                                   (FD_RUNTIME_BORROWED_ACCOUNT_FOOTPRINT                                     + \
     222             :                                                    FD_RUNTIME_INPUT_REGION_TXN_FOOTPRINT(account_lock_limit, direct_mapping) + \
     223             :                                                    FD_RUNTIME_BINCODE_AND_NATIVE_FOOTPRINT                                   + \
     224             :                                                    FD_RUNTIME_MISC_FOOTPRINT)
     225             : 
     226             : /* Convenience macros for common use cases.
     227             : 
     228             :    TODO: If account lock limits are increased to 128, this macro will need to be updated. */
     229             : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_FUZZ    FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(64UL, 0) + FD_SOLFUZZ_MISC_FOOTPRINT
     230             : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_DEFAULT FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(64UL, 0)
     231             : 
     232             : FD_PROTOTYPES_BEGIN
     233             : 
     234             : /* Runtime Helpers ************************************************************/
     235             : 
     236             : /*
     237             :    Returns 0 on success, and non zero otherwise.  On failure, the
     238             :    out values will not be modified.
     239             :  */
     240             : int
     241             : fd_runtime_compute_max_tick_height( ulong   ticks_per_slot,
     242             :                                     ulong   slot,
     243             :                                     ulong * out_max_tick_height /* out */ );
     244             : 
     245             : void
     246             : fd_runtime_update_leaders( fd_bank_t *          bank,
     247             :                            fd_runtime_stack_t * runtime_stack );
     248             : 
     249             : /* Block Level Execution Prep/Finalize ****************************************/
     250             : 
     251             : #define FD_BLOCK_OK                          (0UL)
     252             : #define FD_BLOCK_ERR_INCOMPLETE              (1UL)
     253             : #define FD_BLOCK_ERR_INVALID_ENTRY_HASH      (2UL)
     254             : #define FD_BLOCK_ERR_INVALID_LAST_TICK       (3UL)
     255             : #define FD_BLOCK_ERR_TOO_FEW_TICKS           (4UL)
     256             : #define FD_BLOCK_ERR_TOO_MANY_TICKS          (5UL)
     257             : #define FD_BLOCK_ERR_INVALID_TICK_HASH_COUNT (6UL)
     258             : #define FD_BLOCK_ERR_TRAILING_ENTRY          (7UL)
     259             : #define FD_BLOCK_ERR_DUPLICATE_BLOCK         (8UL)
     260             : 
     261             : /* Load the accounts in the address lookup tables of txn into out_accts_alt */
     262             : int
     263             : fd_runtime_load_txn_address_lookup_tables(
     264             :     fd_txn_t const *          txn,
     265             :     uchar const *             payload,
     266             :     fd_funk_t *               funk,
     267             :     fd_funk_txn_xid_t const * xid,
     268             :     ulong                     slot,
     269             :     fd_slot_hash_t const *    hashes, /* deque */
     270             :     fd_acct_addr_t *          out_accts_alt
     271             : );
     272             : 
     273             : int
     274             : fd_runtime_block_execute_prepare( fd_bank_t *               bank,
     275             :                                   fd_accdb_user_t  *        accdb,
     276             :                                   fd_funk_txn_xid_t const * xid,
     277             :                                   fd_runtime_stack_t *      runtime_stack,
     278             :                                   fd_capture_ctx_t *        capture_ctx );
     279             : 
     280             : void
     281             : fd_runtime_block_execute_finalize( fd_bank_t *               bank,
     282             :                                    fd_accdb_user_t  *        accdb,
     283             :                                    fd_funk_txn_xid_t const * xid,
     284             :                                    fd_capture_ctx_t *        capture_ctx,
     285             :                                    int                       silent );
     286             : 
     287             : /* Transaction Level Execution Management *************************************/
     288             : 
     289             : int
     290             : fd_runtime_pre_execute_check( fd_exec_txn_ctx_t * txn_ctx );
     291             : 
     292             : /* fd_runtime_prepare_and_execute_txn is the main entrypoint from the
     293             :    executor tile. It is responsible for preparing and executing a single
     294             :    transaction. */
     295             : 
     296             : int
     297             : fd_runtime_prepare_and_execute_txn( fd_banks_t *         banks,
     298             :                                     ulong                bank_idx,
     299             :                                     fd_exec_txn_ctx_t *  txn_ctx,
     300             :                                     fd_txn_p_t *         txn,
     301             :                                     fd_capture_ctx_t *   capture_ctx,
     302             :                                     fd_exec_stack_t *    exec_stack,
     303             :                                     fd_exec_accounts_t * exec_accounts,
     304             :                                     uchar *              dumping_mem,
     305             :                                     uchar *              tracing_mem );
     306             : 
     307             : void
     308             : fd_runtime_finalize_txn( fd_funk_t *               funk,
     309             :                          fd_progcache_t *          progcache,
     310             :                          fd_txncache_t *           txncache,
     311             :                          fd_funk_txn_xid_t const * xid,
     312             :                          fd_exec_txn_ctx_t *       txn_ctx,
     313             :                          fd_bank_t *               bank,
     314             :                          fd_capture_ctx_t *        capture_ctx,
     315             :                          ulong *                   tips_out_opt );
     316             : 
     317             : /* Epoch Boundary *************************************************************/
     318             : 
     319             : /* This is roughly Agave's process_new_epoch() which gets called from
     320             :    new_from_parent() for every slot.
     321             :    https://github.com/anza-xyz/agave/blob/v1.18.26/runtime/src/bank.rs#L1483
     322             :    Account changes done by this function are counted towards the first
     323             :    slot of the new epoch (NOT the last slot of the old epoch). */
     324             : void
     325             : fd_runtime_block_pre_execute_process_new_epoch( fd_banks_t *              banks,
     326             :                                                 fd_bank_t *               bank,
     327             :                                                 fd_accdb_user_t *         accdb,
     328             :                                                 fd_funk_txn_xid_t const * xid,
     329             :                                                 fd_capture_ctx_t *        capture_ctx,
     330             :                                                 fd_runtime_stack_t *      runtime_stack,
     331             :                                                 int *                     is_epoch_boundary );
     332             : 
     333             : /* Offline Replay *************************************************************/
     334             : 
     335             : void
     336             : fd_runtime_read_genesis( fd_banks_t *                       banks,
     337             :                          fd_bank_t *                        bank,
     338             :                          fd_accdb_user_t *                  accdb,
     339             :                          fd_funk_txn_xid_t const *          xid,
     340             :                          fd_capture_ctx_t *                 capture_ctx,
     341             :                          fd_hash_t const *                  genesis_hash,
     342             :                          fd_lthash_value_t const *          genesis_lthash,
     343             :                          fd_genesis_solana_global_t const * genesis_block,
     344             :                          fd_runtime_stack_t *               runtime_stack );
     345             : 
     346             : 
     347             : /* Returns whether the specified epoch should use the new vote account
     348             :    keyed leader schedule (returns 1) or the old validator identity keyed
     349             :    leader schedule (returns 0). See SIMD-0180.
     350             :    This is the analogous of Agave's Bank::should_use_vote_keyed_leader_schedule():
     351             :    https://github.com/anza-xyz/agave/blob/v2.3.1/runtime/src/bank.rs#L6148 */
     352             : int
     353             : fd_runtime_should_use_vote_keyed_leader_schedule( fd_bank_t * bank );
     354             : 
     355             : FD_PROTOTYPES_END
     356             : 
     357             : #endif /* HEADER_fd_src_flamenco_runtime_fd_runtime_h */

Generated by: LCOV version 1.14