LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_runtime.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 65 0.0 %
Date: 2025-07-01 05:00:49 Functions: 0 81 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_flamenco_base.h"
       7             : #include "fd_runtime_err.h"
       8             : #include "fd_runtime_init.h"
       9             : #include "fd_rocksdb.h"
      10             : #include "fd_acc_mgr.h"
      11             : #include "fd_hashes.h"
      12             : #include "../features/fd_features.h"
      13             : #include "fd_rent_lists.h"
      14             : #include "../../ballet/poh/fd_poh.h"
      15             : #include "../leaders/fd_leaders.h"
      16             : #include "context/fd_exec_slot_ctx.h"
      17             : #include "context/fd_capture_ctx.h"
      18             : #include "context/fd_exec_txn_ctx.h"
      19             : #include "info/fd_runtime_block_info.h"
      20             : #include "info/fd_instr_info.h"
      21             : #include "../gossip/fd_gossip.h"
      22             : #include "../repair/fd_repair.h"
      23             : #include "../../disco/pack/fd_microblock.h"
      24             : #include "info/fd_microblock_info.h"
      25             : #include "../../ballet/bmtree/fd_wbmtree.h"
      26             : #include "../../ballet/sbpf/fd_sbpf_loader.h"
      27             : #include "fd_runtime_public.h"
      28             : 
      29             : /* Various constant values used by the runtime. */
      30             : 
      31           0 : #define MICRO_LAMPORTS_PER_LAMPORT (1000000UL)
      32             : 
      33             : #define DEFAULT_HASHES_PER_TICK  (12500)
      34           0 : #define UPDATED_HASHES_PER_TICK2 (17500)
      35           0 : #define UPDATED_HASHES_PER_TICK3 (27500)
      36           0 : #define UPDATED_HASHES_PER_TICK4 (47500)
      37           0 : #define UPDATED_HASHES_PER_TICK5 (57500)
      38           0 : #define UPDATED_HASHES_PER_TICK6 (62500)
      39             : 
      40             : #define FD_RUNTIME_TRACE_NONE   (0)
      41             : #define FD_RUNTIME_TRACE_SAVE   (1)
      42             : #define FD_RUNTIME_TRACE_REPLAY (2)
      43             : 
      44           0 : #define FD_RUNTIME_OFFLINE_NUM_ROOT_BLOCKS (6UL) /* 6 root blocks for offline replay */
      45             : 
      46           0 : #define FD_BLOCKHASH_QUEUE_MAX_ENTRIES    (300UL)
      47           0 : #define FD_RECENT_BLOCKHASHES_MAX_ENTRIES (150UL)
      48             : 
      49           0 : #define FD_RENT_EXEMPT_RENT_EPOCH (ULONG_MAX)
      50             : 
      51           0 : #define SECONDS_PER_YEAR ((double)(365.242199 * 24.0 * 60.0 * 60.0))
      52             : 
      53             : /* TODO: increase this to default once we have enough memory to support a 95G status cache. */
      54             : #define MAX_CACHE_TXNS_PER_SLOT (FD_TXNCACHE_DEFAULT_MAX_TRANSACTIONS_PER_SLOT / 8)
      55             : 
      56             : void
      57             : block_finalize_tpool_wrapper( void * para_arg_1,
      58             :                               void * para_arg_2,
      59             :                               void * arg_1,
      60             :                               void * arg_2,
      61             :                               void * arg_3,
      62             :                               void * arg_4 );
      63             : 
      64             : struct fd_execute_txn_task_info {
      65             :   fd_spad_t * *       spads;
      66             :   fd_spad_t *         spad;
      67             :   fd_exec_txn_ctx_t * txn_ctx;
      68             :   fd_txn_p_t *        txn;
      69             :   int                 exec_res;
      70             : };
      71             : typedef struct fd_execute_txn_task_info fd_execute_txn_task_info_t;
      72             : 
      73             : struct fd_raw_block_txn_iter {
      74             :   fd_block_entry_batch_t const * curr_batch;
      75             :   uchar const * orig_data;
      76             :   ulong remaining_batches;
      77             :   ulong remaining_microblocks;
      78             :   ulong remaining_txns;
      79             :   ulong curr_offset;
      80             : 
      81             :   ulong curr_txn_sz;
      82             : };
      83             : 
      84             : typedef struct fd_raw_block_txn_iter fd_raw_block_txn_iter_t;
      85             : 
      86             : struct fd_poh_verifier {
      87             :   union {
      88             :     fd_microblock_hdr_t const * hdr;
      89             :     uchar * raw;
      90             :   } microblock;
      91             :   fd_hash_t const * in_poh_hash;
      92             :   ulong microblk_max_sz;
      93             :   fd_spad_t * spad;
      94             :   int success;
      95             : };
      96             : typedef struct fd_poh_verifier fd_poh_verifier_t;
      97             : 
      98             : /* The below logic is used to size out the memory footprint generated by the
      99             :    runtime during transaction execution. */
     100             : 
     101             : /* The prevailing layout we have in the runtime is the meta followed by
     102             :    the account's data. This struct encodes that layout and asserts that
     103             :    the alignment requirements of the constituents are satisfied. */
     104             : // TODO: Use this struct at allocation sites so it's clear we use this layout
     105             : struct __attribute__((packed)) fd_account_rec {
     106             :   fd_account_meta_t meta;
     107             :   uchar data[];
     108             : };
     109             : typedef struct fd_account_rec fd_account_rec_t;
     110           0 : #define FD_ACCOUNT_REC_ALIGN      (8UL)
     111             : #define FD_ACCOUNT_REC_DATA_ALIGN (8UL)
     112             : FD_STATIC_ASSERT( FD_ACCOUNT_REC_ALIGN>=FD_ACCOUNT_META_ALIGN,     account_rec_meta_align );
     113             : FD_STATIC_ASSERT( FD_ACCOUNT_REC_ALIGN>=FD_ACCOUNT_REC_DATA_ALIGN, account_rec_data_align );
     114             : FD_STATIC_ASSERT( (offsetof(fd_account_rec_t, meta)%FD_ACCOUNT_META_ALIGN)==0,     account_rec_meta_offset );
     115             : FD_STATIC_ASSERT( (offsetof(fd_account_rec_t, data)%FD_ACCOUNT_REC_DATA_ALIGN)==0, account_rec_data_offset );
     116             : 
     117           0 : #define MAX_PERMITTED_DATA_INCREASE (10240UL) // 10KB
     118           0 : #define FD_BPF_ALIGN_OF_U128        (8UL    )
     119             : FD_STATIC_ASSERT( FD_BPF_ALIGN_OF_U128==FD_ACCOUNT_REC_DATA_ALIGN, input_data_align );
     120           0 : #define FD_RUNTIME_INPUT_REGION_ALLOC_ALIGN_UP (16UL)
     121             : 
     122             : /******** These macros bound out memory footprint ********/
     123             : 
     124             : /* The tight upper bound on borrowed account footprint over the
     125             :    execution of a single transaction. */
     126           0 : #define FD_RUNTIME_BORROWED_ACCOUNT_FOOTPRINT (MAX_TX_ACCOUNT_LOCKS * FD_ULONG_ALIGN_UP( FD_ACC_TOT_SZ_MAX, FD_ACCOUNT_REC_ALIGN ))
     127             : 
     128             : /* The tight-ish upper bound on input region footprint over the
     129             :    execution of a single transaction. See input serialization code for
     130             :    reference: fd_bpf_loader_serialization.c
     131             : 
     132             :    This bound is based off of the transaction MTU. We consider the
     133             :    question of what kind of transaction one would construct to
     134             :    maximally bloat the input region.
     135             :    The worst case scenario is when every nested instruction references
     136             :    all unique accounts in the transaction. A transaction can lock a max
     137             :    of MAX_TX_ACCOUNT_LOCKS accounts. Then all remaining input account
     138             :    references are going to be duplicates, which cost 1 byte to specify
     139             :    offset in payload, and which cost 8 bytes during serialization. Then
     140             :    there would be 0 bytes of instruction data, because they exist byte
     141             :    for byte in the raw payload, which is not a worthwhile bloat factor.
     142             :  */
     143             : #define FD_RUNTIME_INPUT_REGION_UNIQUE_ACCOUNT_FOOTPRINT(direct_mapping)                                                                                      \
     144             :                                                         (1UL                         /* dup byte          */                                                + \
     145             :                                                          sizeof(uchar)               /* is_signer         */                                                + \
     146             :                                                          sizeof(uchar)               /* is_writable       */                                                + \
     147             :                                                          sizeof(uchar)               /* executable        */                                                + \
     148             :                                                          sizeof(uint)                /* original_data_len */                                                + \
     149             :                                                          sizeof(fd_pubkey_t)         /* key               */                                                + \
     150             :                                                          sizeof(fd_pubkey_t)         /* owner             */                                                + \
     151             :                                                          sizeof(ulong)               /* lamports          */                                                + \
     152             :                                                          sizeof(ulong)               /* data len          */                                                + \
     153             :                                                          (direct_mapping ? FD_BPF_ALIGN_OF_U128 : FD_ULONG_ALIGN_UP( FD_ACC_SZ_MAX, FD_BPF_ALIGN_OF_U128 )) + \
     154             :                                                          MAX_PERMITTED_DATA_INCREASE                                                                        + \
     155             :                                                          sizeof(ulong))              /* rent_epoch        */
     156             : 
     157             : #define FD_RUNTIME_INPUT_REGION_INSN_FOOTPRINT(account_lock_limit, direct_mapping)                                                                       \
     158           0 :                                               (FD_ULONG_ALIGN_UP( (sizeof(ulong)         /* acct_cnt       */                                          + \
     159           0 :                                                                    account_lock_limit*FD_RUNTIME_INPUT_REGION_UNIQUE_ACCOUNT_FOOTPRINT(direct_mapping) + \
     160           0 :                                                                    sizeof(ulong)         /* instr data len */                                          + \
     161           0 :                                                                                          /* No instr data  */                                            \
     162           0 :                                                                    sizeof(fd_pubkey_t)), /* program id     */                                            \
     163           0 :                                                                    FD_RUNTIME_INPUT_REGION_ALLOC_ALIGN_UP ) + FD_BPF_ALIGN_OF_U128)
     164             : 
     165             : #define FD_RUNTIME_INPUT_REGION_TXN_FOOTPRINT(account_lock_limit, direct_mapping)                                                                           \
     166           0 :                                              ((FD_MAX_INSTRUCTION_STACK_DEPTH*FD_RUNTIME_INPUT_REGION_INSN_FOOTPRINT(account_lock_limit, direct_mapping)) + \
     167           0 :                                               ((FD_TXN_MTU-FD_TXN_MIN_SERIALIZED_SZ-account_lock_limit)*8UL)) /* We can have roughly this much duplicate offsets */
     168             : 
     169             : /* Bincode valloc footprint over the execution of a single transaction.
     170             :    As well as other footprint specific to each native program type.
     171             : 
     172             :    N.B. We know that bincode valloc footprint is bounded, because
     173             :    whenever we alloc something, we advance our pointer into the binary
     174             :    buffer, so eventually we are gonna reach the end of the buffer.
     175             :    This buffer is usually backed by and ultimately bounded in size by
     176             :    either accounts data or the transaction MTU.
     177             : 
     178             :    That being said, it's not obvious what the tight upper bound would
     179             :    be for allocations across all possible execution paths of all native
     180             :    programs, including possible CPIs from native programs.  The
     181             :    footprint estimate here is based on a manual review of our native
     182             :    program implementation.  Note that even if the possible paths remain
     183             :    steady at the Solana protocol level, the footprint is subject to
     184             :    change when we change our implementation.
     185             : 
     186             :    ### Native programs
     187             :    ALUT (migrated to BPF)
     188             :    Loader
     189             :      - rodata for bpf program relocation and validation
     190             :    Compute budget (0 allocations)
     191             :    Config (migrated to BPF)
     192             :    Precompile (0 allocations)
     193             :    Stake
     194             :      - The instruction with the largest footprint is deactivate_delinquent
     195             :        - During instruction decode, no allocations
     196             :        - 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
     197             :    System
     198             :      - system_program_instruction_decode seed
     199             :    Vote
     200             :      - The instruction with the largest footprint is compact vote state update
     201             :        - During instruction decode, this is 9*lockouts_len bytes, MTU bounded
     202             :        - 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)
     203             :    Zk Elgamal (0 allocations)
     204             : 
     205             :    The largest footprint is hence deactivate_delinquent, in which the
     206             :    two get_state() calls dominate the footprint.  In particular, the
     207             :    authorized_voters treaps bloat 40 bytes (epoch+pubkey) in a vote
     208             :    account to 72 bytes (sizeof(fd_vote_authorized_voter_t)) in memory.
     209             :  */
     210           0 : #define FD_RUNTIME_BINCODE_AND_NATIVE_FOOTPRINT (2UL*FD_ACC_SZ_MAX*72UL/40UL)
     211             : 
     212             : /* Misc other footprint. */
     213           0 : #define FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT (FD_MAX_INSTRUCTION_STACK_DEPTH*FD_ULONG_ALIGN_UP(FD_SBPF_SYSCALLS_FOOTPRINT, FD_SBPF_SYSCALLS_ALIGN))
     214             : 
     215             : #ifdef FD_DEBUG_SBPF_TRACES
     216             : #define FD_RUNTIME_VM_TRACE_EVENT_MAX      (1UL<<30)
     217             : #define FD_RUNTIME_VM_TRACE_EVENT_DATA_MAX (2048UL)
     218             : #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() ))
     219             : #else
     220           0 : #define FD_RUNTIME_VM_TRACE_FOOTPRINT (0UL)
     221             : #endif
     222             : 
     223           0 : #define FD_RUNTIME_MISC_FOOTPRINT (FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT+FD_RUNTIME_VM_TRACE_FOOTPRINT)
     224             : 
     225             : /* Now finally, we bound out the footprint of transaction execution. */
     226             : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(account_lock_limit, direct_mapping)                                         \
     227           0 :                                                   (FD_RUNTIME_BORROWED_ACCOUNT_FOOTPRINT                                     + \
     228           0 :                                                    FD_RUNTIME_INPUT_REGION_TXN_FOOTPRINT(account_lock_limit, direct_mapping) + \
     229           0 :                                                    FD_RUNTIME_BINCODE_AND_NATIVE_FOOTPRINT                                   + \
     230           0 :                                                    FD_RUNTIME_MISC_FOOTPRINT)
     231             : 
     232             : /* Convenience macros for common use cases.
     233             : 
     234             :    TODO: If account lock limits are increased to 128, this macro will need to be updated. */
     235           0 : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_FUZZ    FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(64UL, 0)
     236           0 : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_DEFAULT FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(64UL, 0)
     237             : 
     238             : /* Footprint here is dominated by vote account decode.  See above for
     239             :    why 72/40. */
     240           0 : #define FD_RUNTIME_TRANSACTION_FINALIZATION_FOOTPRINT      (FD_ACC_SZ_MAX*72UL/40UL)
     241             : 
     242             : /* The below macros aren't used anywhere, but since the spads are used for PoH tick verification,
     243             :    we ensure that the default spad size is large enough for the wbmtree and leaves */
     244             : 
     245             : #define FD_RUNTIME_MERKLE_LEAF_CNT_MAX (FD_TXN_MAX_PER_SLOT * FD_TXN_ACTUAL_SIG_MAX)
     246             : 
     247             : #define FD_RUNTIME_MERKLE_VERIFICATION_FOOTPRINT FD_RUNTIME_MERKLE_LEAF_CNT_MAX * sizeof(fd_wbmtree32_leaf_t)     /* leaves */   \
     248             :                                                 + sizeof(fd_wbmtree32_t) + sizeof(fd_wbmtree32_node_t)*(FD_RUNTIME_MERKLE_LEAF_CNT_MAX + (FD_RUNTIME_MERKLE_LEAF_CNT_MAX/2)) /* tree footprint */ \
     249             :                                                 + FD_RUNTIME_MERKLE_LEAF_CNT_MAX * (sizeof(fd_ed25519_sig_t) + 1) /* sig mbuf */ \
     250             :                                                 + 1UL + FD_WBMTREE32_ALIGN + alignof(fd_wbmtree32_leaf_t)         /* aligns */
     251             : 
     252             : FD_STATIC_ASSERT( FD_RUNTIME_MERKLE_VERIFICATION_FOOTPRINT <= FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_DEFAULT, merkle verify footprint exceeds txn execution footprint );
     253             : 
     254             : /* Helpers for runtime public frame management. */
     255             : 
     256             : /* Helpers for runtime spad frame management. */
     257             : struct fd_runtime_spad_verify_handle_private {
     258             :   fd_spad_t *         spad;
     259             :   fd_exec_txn_ctx_t * txn_ctx;
     260             : };
     261             : typedef struct fd_runtime_spad_verify_handle_private fd_runtime_spad_verify_handle_private_t;
     262             : 
     263             : static inline void
     264           0 : fd_runtime_spad_private_frame_end( fd_runtime_spad_verify_handle_private_t * _spad_handle ) {
     265             :   /* fd_spad_verify() returns 0 if everything looks good, and non-zero
     266             :      otherwise.
     267             : 
     268             :      Since the fast spad alloc API doesn't check for or indicate an OOM
     269             :      situation and is going to happily permit an OOB alloc, we need
     270             :      some way of detecting that. Moreover, we would also like to detect
     271             :      unbalanced frame push/pop or usage of more frames than allowed.
     272             :      While surrounding the spad with guard regions will help detect the
     273             :      former, it won't necessarily catch the latter.
     274             : 
     275             :      On compliant transactions, fd_spad_verify() isn't all that
     276             :      expensive.  Nonetheless, We invoke fd_spad_verify() only at the
     277             :      peak of memory usage, and not gratuitously everywhere. One peak
     278             :      would be right before we do the most deeply nested spad frame pop.
     279             :      However, we do pops through compiler-inserted cleanup functions
     280             :      that take only a single pointer, so we define this helper function
     281             :      to access the needed context info.  The end result is that we do
     282             :      super fast spad calls everywhere in the runtime, and every now and
     283             :      then we invoke verify to check things. */
     284             :   /* -1UL because spad pop is called after instr stack pop. */
     285           0 :   if( FD_UNLIKELY( _spad_handle->txn_ctx->instr_stack_sz>=FD_MAX_INSTRUCTION_STACK_DEPTH-1UL && fd_spad_verify( _spad_handle->txn_ctx->spad ) ) ) {
     286           0 :     uchar const * txn_signature = (uchar const *)fd_txn_get_signatures( _spad_handle->txn_ctx->txn_descriptor, _spad_handle->txn_ctx->_txn_raw->raw );
     287           0 :     FD_BASE58_ENCODE_64_BYTES( txn_signature, sig );
     288           0 :     FD_LOG_ERR(( "spad corrupted or overflown on transaction %s", sig ));
     289           0 :   }
     290           0 :   fd_spad_pop( _spad_handle->spad );
     291           0 : }
     292             : 
     293           0 : #define FD_RUNTIME_TXN_SPAD_FRAME_BEGIN(_spad, _txn_ctx) do {                                                        \
     294           0 :   fd_runtime_spad_verify_handle_private_t _spad_handle __attribute__((cleanup(fd_runtime_spad_private_frame_end))) = \
     295           0 :     (fd_runtime_spad_verify_handle_private_t) { .spad = _spad, .txn_ctx = _txn_ctx };                                \
     296           0 :   fd_spad_push( _spad_handle.spad );                                                                                 \
     297           0 :   do
     298             : 
     299           0 : #define FD_RUNTIME_TXN_SPAD_FRAME_END while(0); } while(0)
     300             : 
     301             : FD_PROTOTYPES_BEGIN
     302             : 
     303             : /* Runtime Helpers ************************************************************/
     304             : 
     305             : /*
     306             :    Returns 0 on success, and non zero otherwise.  On failure, the
     307             :    out values will not be modified.
     308             :  */
     309             : int
     310             : fd_runtime_compute_max_tick_height( ulong   ticks_per_slot,
     311             :                                     ulong   slot,
     312             :                                     ulong * out_max_tick_height /* out */ );
     313             : 
     314             : void
     315             : fd_runtime_update_leaders( fd_bank_t * bank,
     316             :                            ulong       slot,
     317             :                            fd_spad_t * runtime_spad );
     318             : 
     319             : /* TODO: Invoked by fd_executor: layering violation. Rent logic is deprecated
     320             :    and will be torn out entirely very soon. */
     321             : ulong
     322             : fd_runtime_collect_rent_from_account( fd_epoch_schedule_t const * schedule,
     323             :                                       fd_rent_t const *           rent,
     324             :                                       double                      slots_per_year,
     325             :                                       fd_txn_account_t *          acc,
     326             :                                       ulong                       epoch );
     327             : 
     328             : void
     329             : fd_runtime_update_slots_per_epoch( fd_bank_t * bank,
     330             :                                    ulong       slots_per_epoch );
     331             : 
     332             : /* Block Level Execution Prep/Finalize ****************************************/
     333             : 
     334           0 : #define FD_BLOCK_OK                          (0UL)
     335             : #define FD_BLOCK_ERR_INCOMPLETE              (1UL)
     336             : #define FD_BLOCK_ERR_INVALID_ENTRY_HASH      (2UL)
     337             : #define FD_BLOCK_ERR_INVALID_LAST_TICK       (3UL)
     338           0 : #define FD_BLOCK_ERR_TOO_FEW_TICKS           (4UL)
     339           0 : #define FD_BLOCK_ERR_TOO_MANY_TICKS          (5UL)
     340           0 : #define FD_BLOCK_ERR_INVALID_TICK_HASH_COUNT (6UL)
     341           0 : #define FD_BLOCK_ERR_TRAILING_ENTRY          (7UL)
     342             : #define FD_BLOCK_ERR_DUPLICATE_BLOCK         (8UL)
     343             : 
     344             : /*
     345             :    https://github.com/anza-xyz/agave/blob/v2.1.0/ledger/src/blockstore_processor.rs#L1096
     346             :    This function assumes a full block.
     347             :    This needs to be called after epoch processing to get the up to date
     348             :    hashes_per_tick.
     349             : 
     350             :    Provide scratch memory >= the max size of a batch to use. This is because we can only
     351             :    assemble shreds by batch, so we iterate and assemble shreds by batch in this function
     352             :    without needing the caller to do so.
     353             :  */
     354             : ulong
     355             : fd_runtime_block_verify_ticks( fd_blockstore_t * blockstore,
     356             :                                ulong             slot,
     357             :                                uchar *           block_data_mem,
     358             :                                ulong             block_data_sz,
     359             :                                ulong             tick_height,
     360             :                                ulong             max_tick_height,
     361             :                                ulong             hashes_per_tick );
     362             : 
     363             : /* The following microblock-level functions are exposed and non-static due to also being used for fd_replay.
     364             :    The block-level equivalent functions, on the other hand, are mostly static as they are only used
     365             :    for offline replay */
     366             : 
     367             : /* extra fine-grained streaming tick verification */
     368             : int
     369             : fd_runtime_microblock_verify_ticks( fd_blockstore_t *           blockstore,
     370             :                                     ulong                       slot,
     371             :                                     fd_microblock_hdr_t const * hdr,
     372             :                                     bool               slot_complete,
     373             :                                     ulong              tick_height,
     374             :                                     ulong              max_tick_height,
     375             :                                     ulong              hashes_per_tick );
     376             : 
     377             : /*
     378             :    fd_runtime_microblock_verify_read_write_conflicts verifies that a
     379             :    list of txns (e.g., those in a microblock) do not have read-write
     380             :    or write-write conflits. FD_TXN_CONFLICT_MAP_MAX_NACCT defines a
     381             :    conservative estimation of the number of accounts touched by txns
     382             :    in one slot. Given the conservative estimation, the footprint of
     383             :    the account map (fd_conflict_detect_map) is about 2112MB. One can
     384             :    certainly use a better estimation leading to a smaller footprint.
     385             : 
     386             :    this function corresponds to try_lock_accounts in Agave which
     387             :    detects transaction conflicts:
     388             :    https://github.com/anza-xyz/agave/blob/v2.2.3/runtime/src/bank.rs
     389             :    #L3145
     390             : 
     391             :    Specifically, from the replay stage of Agave, the control flow is
     392             :    (1) replay_blockstore_into_bank: https://github.com/anza-xyz/agave/
     393             :    blob/v2.2.3/core/src/replay_stage.rs#L2232
     394             :    (2) confirm_slot: https://github.com/anza-xyz/agave/blob/v2.2.3/
     395             :    ledger/src/blockstore_processor.rs#L1561
     396             :    (3) confirm_slot_entries: https://github.com/anza-xyz/agave/blob/
     397             :    v2.2.3/ledger/src/blockstore_processor.rs#L1609
     398             :    (4) process_entries: https://github.com/anza-xyz/agave/blob/v2.2.3/
     399             :    ledger/src/blockstore_processor.rs#L704
     400             :    (5) queue_batches_with_lock_retry: https://github.com/anza-xyz/agave/
     401             :    blob/v2.2.3/ledger/src/blockstore_processor.rs#L789
     402             :    (6) bank.try_lock_accounts is called in queue_batches_with_lock_retry
     403             :    (7) this try_lock_accounts eventually calls another try_lock_accounts,
     404             :        (see https://github.com/anza-xyz/agave/blob/v2.2.3/accounts-db/src
     405             :        /account_locks.rs#L24), which acquires the locks and returns
     406             :        TransactionError::AccountInUse if r-w or w-w conflict is detected
     407             :    (8) when calling try_lock_accounts, function accounts_with_is_writable
     408             :    is used to decide whether an account is writable (see https://github.
     409             :    com/anza-xyz/agave/blob/v2.2.3/accounts-db/src/accounts.rs#L605) which
     410             :    internally calls the is_writable function depending on whether the txn
     411             :    is legacy or V0:
     412             : 
     413             :    is_writable for legacy: https://github.com/anza-xyz/solana-sdk/blob/
     414             :    message%40v2.2.1/message/src/sanitized.rs#L75
     415             : 
     416             :    is_writable for V0: https://github.com/anza-xyz/solana-sdk/blob/
     417             :    message%40v2.2.1/message/src/versions/v0/loaded.rs#L152
     418             : 
     419             :    In both cases, Agave does the following check in addition to whether
     420             :    an account has been specified as writable in the transaction message
     421             :    (https://github.com/anza-xyz/solana-sdk/blob/message%40v2.2.1/message
     422             :    /src/versions/v0/loaded.rs#L146). This additional check is handled by
     423             :    function fd_txn_account_is_writable_idx_flat in our code.
     424             : 
     425             :    txns is an array containing txn_cnt transactions in fd_txn_p_t type;
     426             :    acct_map is used to detect conflicts and acct_arr is used to clear the
     427             :    map before the function returns; funk and funk_txn are used to read
     428             :    Solana accounts for address lookup tables; slot and slot_hashes are
     429             :    needed for checking certain bounds in the address lookup table system
     430             :    program; features is needed in fd_txn_account_is_writable_idx_flat to
     431             :    decide whether a writable account is demoted to read-only.
     432             : 
     433             :    If an error occurs in runtime, the function returns the runtime error.
     434             :    If there's no conflict, the return value is FD_RUNTIME_EXECUTE_SUCCESS
     435             :    and out_conflict_detected will be 0. If there's a conflict, the return
     436             :    value is FD_RUNTIME_TXN_ERR_ACCOUNT_IN_USE and out_conflict_detected
     437             :    will be 1 (read-write) or 2 (write-write), and out_conflict_addr_opt,
     438             :    if not NULL, will hold the account address causing the conflict.
     439             :  */
     440             : struct fd_conflict_detect_ele {
     441             :   fd_acct_addr_t key;
     442             :   uchar          writable;
     443             : };
     444             : typedef struct fd_conflict_detect_ele fd_conflict_detect_ele_t;
     445           0 : #define FD_TXN_CONFLICT_MAP_SEED        (0UL)
     446             : #define FD_TXN_CONFLICT_MAP_MAX_NACCT   (FD_SHRED_DATA_PAYLOAD_MAX_PER_SLOT / FD_TXN_MIN_SERIALIZED_SZ * FD_TXN_ACCT_ADDR_MAX)
     447             : 
     448             : static const fd_acct_addr_t fd_acct_addr_null = {.b={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}};
     449             : #define MAP_NAME              fd_conflict_detect_map
     450           0 : #define MAP_KEY_T             fd_acct_addr_t
     451           0 : #define MAP_T                 fd_conflict_detect_ele_t
     452           0 : #define MAP_HASH_T            ulong
     453           0 : #define MAP_KEY_NULL          (fd_acct_addr_null)
     454           0 : #define MAP_KEY_EQUAL(k0,k1)  (0==memcmp((k0).b,(k1).b,32))
     455           0 : #define MAP_KEY_HASH(key)     fd_hash( FD_TXN_CONFLICT_MAP_SEED, key.b, 32 )
     456           0 : #define MAP_KEY_INVAL(k)      (0==memcmp(&fd_acct_addr_null, (k).b, 32))
     457             : #define MAP_KEY_EQUAL_IS_SLOW 0
     458             : #define MAP_MEMOIZE           0
     459             : 
     460             : #include "../../util/tmpl/fd_map_dynamic.c"
     461             : 
     462           0 : #define FD_RUNTIME_NO_CONFLICT_DETECTED          0
     463           0 : #define FD_RUNTIME_READ_WRITE_CONFLICT_DETECTED  1
     464           0 : #define FD_RUNTIME_WRITE_WRITE_CONFLICT_DETECTED 2
     465             : 
     466             : int
     467             : fd_runtime_microblock_verify_read_write_conflicts( fd_txn_p_t *               txns,
     468             :                                                    ulong                      txn_cnt,
     469             :                                                    fd_conflict_detect_ele_t * acct_map,
     470             :                                                    fd_acct_addr_t *           acct_arr,
     471             :                                                    fd_funk_t *                funk,
     472             :                                                    fd_funk_txn_t *            funk_txn,
     473             :                                                    ulong                      slot,
     474             :                                                    fd_slot_hash_t *           slot_hashes,
     475             :                                                    fd_features_t *            features,
     476             :                                                    int *                      out_conflict_detected,
     477             :                                                    fd_acct_addr_t *           out_conflict_addr_opt );
     478             : 
     479             : /* Load the accounts in the address lookup tables of txn into out_accts_alt */
     480             : int
     481             : fd_runtime_load_txn_address_lookup_tables( fd_txn_t const * txn,
     482             :                                            uchar const *    payload,
     483             :                                            fd_funk_t *      funk,
     484             :                                            fd_funk_txn_t *  funk_txn,
     485             :                                            ulong            slot,
     486             :                                            fd_slot_hash_t * hashes,
     487             :                                            fd_acct_addr_t * out_accts_alt );
     488             : 
     489             : /* fd_runtime_poh_verify is responsible for verifying poh hashes while
     490             :    streaming in microblocks. */
     491             : 
     492             : void
     493             : fd_runtime_poh_verify( fd_poh_verifier_t * poh_info );
     494             : 
     495             : int
     496             : fd_runtime_block_execute_prepare( fd_exec_slot_ctx_t * slot_ctx,
     497             :                                   fd_blockstore_t *    blockstore,
     498             :                                   fd_spad_t *          runtime_spad );
     499             : 
     500             : void
     501             : fd_runtime_block_execute_finalize_start( fd_exec_slot_ctx_t *             slot_ctx,
     502             :                                          fd_spad_t *                      runtime_spad,
     503             :                                          fd_accounts_hash_task_data_t * * task_data,
     504             :                                          ulong                            lt_hash_cnt );
     505             : 
     506             : int
     507             : fd_runtime_block_execute_finalize_finish( fd_exec_slot_ctx_t *             slot_ctx,
     508             :                                           fd_capture_ctx_t *               capture_ctx,
     509             :                                           fd_runtime_block_info_t const *  block_info,
     510             :                                           fd_spad_t *                      runtime_spad,
     511             :                                           fd_accounts_hash_task_data_t *   task_data,
     512             :                                           ulong                            lt_hash_cnt );
     513             : 
     514             : int
     515             : fd_runtime_block_execute_finalize_para( fd_exec_slot_ctx_t *             slot_ctx,
     516             :                                         fd_capture_ctx_t *               capture_ctx,
     517             :                                         fd_runtime_block_info_t const *  block_info,
     518             :                                         ulong                            worker_cnt,
     519             :                                         fd_spad_t *                      runtime_spad,
     520             :                                         fd_exec_para_cb_ctx_t *          exec_para_ctx );
     521             : 
     522             : /* Transaction Level Execution Management *************************************/
     523             : 
     524             : /* fd_runtime_prepare_txns_start and fd_runtime_pre_execute_check are only
     525             :    publicly exposed for the fuzzing harnesses. These functions are responsible
     526             :    for various transaction sanitization checks. */
     527             : 
     528             : int
     529             : fd_runtime_prepare_txns_start( fd_exec_slot_ctx_t *         slot_ctx,
     530             :                                fd_execute_txn_task_info_t * task_info,
     531             :                                fd_txn_p_t *                 txns,
     532             :                                ulong                        txn_cnt,
     533             :                                fd_spad_t *                  runtime_spad );
     534             : 
     535             : void
     536             : fd_runtime_pre_execute_check( fd_execute_txn_task_info_t * task_info,
     537             :                               uchar                        dump_txn );
     538             : 
     539             : /* fd_runtime_process_txns is responsible for end-to-end preparing, executing,
     540             :    and finalizing a list of transactions. It will execute all of the
     541             :    transactions on a single core. */
     542             : int
     543             : fd_runtime_process_txns( fd_exec_slot_ctx_t * slot_ctx,
     544             :                          fd_capture_ctx_t *   capture_ctx,
     545             :                          fd_txn_p_t *         txns,
     546             :                          ulong                txn_cnt,
     547             :                          fd_spad_t *          exec_spad,
     548             :                          fd_spad_t *          runtime_spad );
     549             : 
     550             : /* fd_runtime_execute_txns_in_microblock_stream is responsible for end-to-end
     551             :    preparing, executing and finalizng a list of transactions. It assumes that
     552             :    all transactions are conflict-free. */
     553             : 
     554             : int
     555             : fd_runtime_process_txns_in_microblock_stream( fd_exec_slot_ctx_t * slot_ctx,
     556             :                                               fd_capture_ctx_t *   capture_ctx,
     557             :                                               fd_txn_p_t *         all_txns,
     558             :                                               ulong                total_txn_cnt,
     559             :                                               fd_tpool_t *         tpool,
     560             :                                               fd_spad_t * *        exec_spads,
     561             :                                               ulong                exec_spad_cnt,
     562             :                                               fd_spad_t *          runtime_spad,
     563             :                                               fd_cost_tracker_t *  cost_tracker_opt );
     564             : 
     565             : void
     566             : fd_runtime_finalize_txn( fd_funk_t *                  funk,
     567             :                          fd_funk_txn_t *              funk_txn,
     568             :                          fd_execute_txn_task_info_t * task_info,
     569             :                          fd_spad_t *                  finalize_spad,
     570             :                          fd_bank_t *                  bank );
     571             : 
     572             : /* Epoch Boundary *************************************************************/
     573             : 
     574             : uint
     575             : fd_runtime_is_epoch_boundary( fd_exec_slot_ctx_t * slot_ctx,
     576             :                               ulong                curr_slot,
     577             :                               ulong                prev_slot );
     578             : 
     579             : /*
     580             :    This is roughly Agave's process_new_epoch() which gets called from
     581             :    new_from_parent() for every slot.
     582             :    https://github.com/anza-xyz/agave/blob/v1.18.26/runtime/src/bank.rs#L1483
     583             :    This needs to be called after funk_txn_prepare() because the accounts
     584             :    that we modify when processing a new epoch need to be hashed into
     585             :    the bank hash.
     586             :  */
     587             : void
     588             : fd_runtime_block_pre_execute_process_new_epoch( fd_exec_slot_ctx_t * slot_ctx,
     589             :                                                 fd_tpool_t *         tpool,
     590             :                                                 fd_spad_t * *        exec_spads,
     591             :                                                 ulong                exec_spad_cnt,
     592             :                                                 fd_spad_t *          runtime_spad,
     593             :                                                 int *                is_epoch_boundary );
     594             : 
     595             : /* This function is responsible for inserting fresh entries or updating existing entries in the program cache.
     596             :    When the client boots up, the program cache is empty. As programs get invoked, this function is responsible
     597             :    for verifying and inserting these programs into the cache. Additionally, this function performs reverification
     598             :    checks for every existing program that is invoked after an epoch boundary once per program per epoch, and invalidates
     599             :    any programs that fail reverification.
     600             : 
     601             :    When the cluster's feature set changes at an epoch, there is a possibility that existing programs
     602             :    fail new SBPF / ELF header checks. Therefore, after every epoch, we should reverify all programs
     603             :    and update our program cache so that users cannot invoke those old programs. Since iterating through
     604             :    all programs every single epoch is expensive, we adopt a lazy approach where we reverify programs as they
     605             :    are referenced in transactions, since only a small subset of all programs are actually referenced at any
     606             :    time. We also make sure each program is only verified once per epoch, so repeated executions of a
     607             :    program within the same epoch will only trigger verification once at the very first invocation.
     608             : 
     609             :    Note that ALUTs must be resolved because programs referenced in ALUTs can be invoked via CPI. */
     610             : void
     611             : fd_runtime_update_program_cache( fd_exec_slot_ctx_t * slot_ctx,
     612             :                                  fd_txn_p_t const *   txn_p,
     613             :                                  fd_spad_t *          runtime_spad );
     614             : 
     615             : /* Debugging Tools ************************************************************/
     616             : 
     617             : void
     618             : fd_runtime_checkpt( fd_capture_ctx_t *   capture_ctx,
     619             :                     fd_exec_slot_ctx_t * slot_ctx,
     620             :                     ulong                slot );
     621             : 
     622             : /* Block Parsing **************************************************************/
     623             : 
     624             : /* Live Replay APIs */
     625             : 
     626             : fd_raw_block_txn_iter_t
     627             : fd_raw_block_txn_iter_init( uchar const *                  orig_data,
     628             :                             fd_block_entry_batch_t const * batches,
     629             :                             ulong                          batch_cnt );
     630             : 
     631             : ulong
     632             : fd_raw_block_txn_iter_done( fd_raw_block_txn_iter_t iter );
     633             : 
     634             : fd_raw_block_txn_iter_t
     635             : fd_raw_block_txn_iter_next( fd_raw_block_txn_iter_t iter );
     636             : 
     637             : void
     638             : fd_raw_block_txn_iter_ele( fd_raw_block_txn_iter_t iter, fd_txn_p_t * out_txn );
     639             : 
     640             : /* Offline Replay *************************************************************/
     641             : 
     642             : int
     643             : fd_runtime_block_eval_tpool( fd_exec_slot_ctx_t * slot_ctx,
     644             :                              ulong                slot,
     645             :                              fd_block_t *         block,
     646             :                              fd_capture_ctx_t *   capture_ctx,
     647             :                              fd_tpool_t *         tpool,
     648             :                              ulong                scheduler,
     649             :                              ulong *              txn_cnt,
     650             :                              fd_spad_t * *        spads,
     651             :                              ulong                spads_cnt,
     652             :                              fd_spad_t *          runtime_spad,
     653             :                              fd_blockstore_t *    blockstore );
     654             : 
     655             : int
     656             : fd_runtime_block_execute_tpool( fd_exec_slot_ctx_t *            slot_ctx,
     657             :                                 fd_blockstore_t *               blockstore,
     658             :                                 fd_capture_ctx_t *              capture_ctx,
     659             :                                 fd_runtime_block_info_t const * block_info,
     660             :                                 fd_tpool_t *                    tpool,
     661             :                                 fd_spad_t * *                   exec_spads,
     662             :                                 ulong                           exec_spad_cnt,
     663             :                                 fd_spad_t *                     runtime_spad );
     664             : 
     665             : /* Genesis ********************************************************************/
     666             : 
     667             : void
     668             : fd_runtime_read_genesis( fd_exec_slot_ctx_t * slot_ctx,
     669             :                          char const *         genesis_filepath,
     670             :                          uchar                is_snapshot,
     671             :                          fd_capture_ctx_t *   capture_ctx,
     672             :                          fd_spad_t *          spad );
     673             : 
     674             : FD_PROTOTYPES_END
     675             : 
     676             : #endif /* HEADER_fd_src_flamenco_runtime_fd_runtime_h */

Generated by: LCOV version 1.14