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

Generated by: LCOV version 1.14