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

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_runtime_fd_runtime_h
       2             : #define HEADER_fd_src_flamenco_runtime_fd_runtime_h
       3             : 
       4             : #include "stdarg.h"
       5             : 
       6             : #include "fd_runtime_err.h"
       7             : #include "fd_runtime_init.h"
       8             : #include "fd_rocksdb.h"
       9             : #include "fd_acc_mgr.h"
      10             : #include "fd_hashes.h"
      11             : #include "../features/fd_features.h"
      12             : #include "context/fd_capture_ctx.h"
      13             : #include "context/fd_exec_txn_ctx.h"
      14             : #include "info/fd_runtime_block_info.h"
      15             : #include "info/fd_instr_info.h"
      16             : #include "../../disco/pack/fd_microblock.h"
      17             : #include "info/fd_microblock_info.h"
      18             : #include "../../ballet/sbpf/fd_sbpf_loader.h"
      19             : #include "../vm/fd_vm_base.h"
      20             : 
      21             : /* Various constant values used by the runtime. */
      22             : 
      23           0 : #define MICRO_LAMPORTS_PER_LAMPORT (1000000UL)
      24             : 
      25           0 : #define DEFAULT_HASHES_PER_TICK  (12500)
      26             : #define UPDATED_HASHES_PER_TICK2 (17500)
      27             : #define UPDATED_HASHES_PER_TICK3 (27500)
      28             : #define UPDATED_HASHES_PER_TICK4 (47500)
      29             : #define UPDATED_HASHES_PER_TICK5 (57500)
      30             : #define UPDATED_HASHES_PER_TICK6 (62500)
      31             : 
      32             : #define FD_RUNTIME_TRACE_NONE   (0)
      33             : #define FD_RUNTIME_TRACE_SAVE   (1)
      34             : #define FD_RUNTIME_TRACE_REPLAY (2)
      35             : 
      36             : #define FD_RUNTIME_OFFLINE_NUM_ROOT_BLOCKS (6UL) /* 6 root blocks for offline replay */
      37             : 
      38             : #define FD_RENT_EXEMPT_RENT_EPOCH (ULONG_MAX)
      39             : 
      40           0 : #define SECONDS_PER_YEAR ((double)(365.242199 * 24.0 * 60.0 * 60.0))
      41             : 
      42             : /*
      43             :  * fd_block_entry_batch_t is a microblock/entry batch within a block.
      44             :  * The offset is relative to the start of the block's data region,
      45             :  * and indicates where the batch ends.  The (exclusive) end offset of
      46             :  * batch i is the (inclusive) start offset of batch i+1.  The 0th batch
      47             :  * always starts at offset 0.
      48             :  * On the wire, the presence of one of the COMPLETE flags in a data
      49             :  * shred marks the end of a batch.
      50             :  * In other words, batch ends are aligned with shred ends, and batch
      51             :  * starts are aligned with shred starts.  Usually a batch comprises
      52             :  * multiple shreds, and a block comprises multiple batches.
      53             :  * This information is useful because bincode deserialization needs to
      54             :  * be performed on a per-batch basis.  Precisely a single array of
      55             :  * microblocks/entries is expected to be deserialized from a batch.
      56             :  * Trailing bytes in each batch are ignored by default.
      57             :  */
      58             : struct fd_block_entry_batch {
      59             :   ulong end_off; /* exclusive */
      60             : };
      61             : typedef struct fd_block_entry_batch fd_block_entry_batch_t;
      62             : 
      63             : /* The below logic is used to size out the memory footprint generated by the
      64             :    runtime during transaction execution. */
      65             : 
      66             : /* The prevailing layout we have in the runtime is the meta followed by
      67             :    the account's data. This struct encodes that layout and asserts that
      68             :    the alignment requirements of the constituents are satisfied. */
      69             : // TODO: Use this struct at allocation sites so it's clear we use this layout
      70             : struct __attribute__((packed)) fd_account_rec {
      71             :   fd_account_meta_t meta;
      72             :   uchar data[] __attribute__((aligned(8)));
      73             : };
      74             : typedef struct fd_account_rec fd_account_rec_t;
      75           0 : #define FD_ACCOUNT_REC_ALIGN      (8UL)
      76             : #define FD_ACCOUNT_REC_DATA_ALIGN (8UL)
      77             : FD_STATIC_ASSERT( FD_ACCOUNT_REC_ALIGN>=alignof(fd_account_meta_t), account_rec_meta_align );
      78             : FD_STATIC_ASSERT( FD_ACCOUNT_REC_ALIGN>=FD_ACCOUNT_REC_DATA_ALIGN,  account_rec_data_align );
      79             : FD_STATIC_ASSERT( (offsetof(fd_account_rec_t, meta)%alignof(fd_account_meta_t))==0, account_rec_meta_offset );
      80             : FD_STATIC_ASSERT( (offsetof(fd_account_rec_t, data)%FD_ACCOUNT_REC_DATA_ALIGN )==0, account_rec_data_offset );
      81             : 
      82           0 : #define MAX_PERMITTED_DATA_INCREASE (10240UL) // 10KB
      83          24 : #define FD_BPF_ALIGN_OF_U128        (8UL    )
      84             : FD_STATIC_ASSERT( FD_BPF_ALIGN_OF_U128==FD_ACCOUNT_REC_DATA_ALIGN, input_data_align );
      85           0 : #define FD_RUNTIME_INPUT_REGION_ALLOC_ALIGN_UP (16UL)
      86             : 
      87             : /******** These macros bound out memory footprint ********/
      88             : 
      89             : /* The tight upper bound on borrowed account footprint over the
      90             :    execution of a single transaction. */
      91          24 : #define FD_RUNTIME_BORROWED_ACCOUNT_FOOTPRINT (MAX_TX_ACCOUNT_LOCKS * FD_ULONG_ALIGN_UP( FD_ACC_TOT_SZ_MAX, FD_ACCOUNT_REC_ALIGN ))
      92             : 
      93             : /* The tight-ish upper bound on input region footprint over the
      94             :    execution of a single transaction. See input serialization code for
      95             :    reference: fd_bpf_loader_serialization.c
      96             : 
      97             :    This bound is based off of the transaction MTU. We consider the
      98             :    question of what kind of transaction one would construct to
      99             :    maximally bloat the input region.
     100             :    The worst case scenario is when every nested instruction references
     101             :    all unique accounts in the transaction. A transaction can lock a max
     102             :    of MAX_TX_ACCOUNT_LOCKS accounts. Then all remaining input account
     103             :    references are going to be duplicates, which cost 1 byte to specify
     104             :    offset in payload, and which cost 8 bytes during serialization. Then
     105             :    there would be 0 bytes of instruction data, because they exist byte
     106             :    for byte in the raw payload, which is not a worthwhile bloat factor.
     107             :  */
     108             : #define FD_RUNTIME_INPUT_REGION_UNIQUE_ACCOUNT_FOOTPRINT(direct_mapping)                                                                                              \
     109             :                                                         (1UL                         /* dup byte          */                                                        + \
     110             :                                                          sizeof(uchar)               /* is_signer         */                                                        + \
     111             :                                                          sizeof(uchar)               /* is_writable       */                                                        + \
     112             :                                                          sizeof(uchar)               /* executable        */                                                        + \
     113             :                                                          sizeof(uint)                /* original_data_len */                                                        + \
     114             :                                                          sizeof(fd_pubkey_t)         /* key               */                                                        + \
     115             :                                                          sizeof(fd_pubkey_t)         /* owner             */                                                        + \
     116             :                                                          sizeof(ulong)               /* lamports          */                                                        + \
     117             :                                                          sizeof(ulong)               /* data len          */                                                        + \
     118             :                                                          (direct_mapping ? FD_BPF_ALIGN_OF_U128 : FD_ULONG_ALIGN_UP( FD_RUNTIME_ACC_SZ_MAX, FD_BPF_ALIGN_OF_U128 )) + \
     119             :                                                          MAX_PERMITTED_DATA_INCREASE                                                                                + \
     120             :                                                          sizeof(ulong))              /* rent_epoch        */
     121             : 
     122             : #define FD_RUNTIME_INPUT_REGION_INSN_FOOTPRINT(account_lock_limit, direct_mapping)                                                                       \
     123          24 :                                               (FD_ULONG_ALIGN_UP( (sizeof(ulong)         /* acct_cnt       */                                          + \
     124          24 :                                                                    account_lock_limit*FD_RUNTIME_INPUT_REGION_UNIQUE_ACCOUNT_FOOTPRINT(direct_mapping) + \
     125          24 :                                                                    sizeof(ulong)         /* instr data len */                                          + \
     126          24 :                                                                                          /* No instr data  */                                            \
     127          24 :                                                                    sizeof(fd_pubkey_t)), /* program id     */                                            \
     128          24 :                                                                    FD_RUNTIME_INPUT_REGION_ALLOC_ALIGN_UP ) + FD_BPF_ALIGN_OF_U128)
     129             : 
     130             : #define FD_RUNTIME_INPUT_REGION_TXN_FOOTPRINT(account_lock_limit, direct_mapping)                                                                           \
     131          24 :                                              ((FD_MAX_INSTRUCTION_STACK_DEPTH*FD_RUNTIME_INPUT_REGION_INSN_FOOTPRINT(account_lock_limit, direct_mapping)) + \
     132          24 :                                               ((FD_TXN_MTU-FD_TXN_MIN_SERIALIZED_SZ-account_lock_limit)*8UL)) /* We can have roughly this much duplicate offsets */
     133             : 
     134             : /* Bincode valloc footprint over the execution of a single transaction.
     135             :    As well as other footprint specific to each native program type.
     136             : 
     137             :    N.B. We know that bincode valloc footprint is bounded, because
     138             :    whenever we alloc something, we advance our pointer into the binary
     139             :    buffer, so eventually we are gonna reach the end of the buffer.
     140             :    This buffer is usually backed by and ultimately bounded in size by
     141             :    either accounts data or the transaction MTU.
     142             : 
     143             :    That being said, it's not obvious what the tight upper bound would
     144             :    be for allocations across all possible execution paths of all native
     145             :    programs, including possible CPIs from native programs.  The
     146             :    footprint estimate here is based on a manual review of our native
     147             :    program implementation.  Note that even if the possible paths remain
     148             :    steady at the Solana protocol level, the footprint is subject to
     149             :    change when we change our implementation.
     150             : 
     151             :    ### Native programs
     152             :    ALUT (migrated to BPF)
     153             :    Loader
     154             :      - rodata for bpf program relocation and validation
     155             :    Compute budget (0 allocations)
     156             :    Config (migrated to BPF)
     157             :    Precompile (0 allocations)
     158             :    Stake
     159             :      - The instruction with the largest footprint is deactivate_delinquent
     160             :        - During instruction decode, no allocations
     161             :        - 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
     162             :    System
     163             :      - system_program_instruction_decode seed
     164             :    Vote
     165             :      - The instruction with the largest footprint is compact vote state update
     166             :        - During instruction decode, this is 9*lockouts_len bytes, MTU bounded
     167             :        - 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)
     168             :    Zk Elgamal (0 allocations)
     169             : 
     170             :    The largest footprint is hence deactivate_delinquent, in which the
     171             :    two get_state() calls dominate the footprint.  In particular, the
     172             :    authorized_voters treaps bloat 40 bytes (epoch+pubkey) in a vote
     173             :    account to 72 bytes (sizeof(fd_vote_authorized_voter_t)) in memory.
     174             :  */
     175          24 : #define FD_RUNTIME_BINCODE_AND_NATIVE_FOOTPRINT (2UL*FD_RUNTIME_ACC_SZ_MAX*72UL/40UL)
     176             : 
     177             : /* Misc other footprint. */
     178          24 : #define FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT (FD_MAX_INSTRUCTION_STACK_DEPTH*FD_ULONG_ALIGN_UP(FD_SBPF_SYSCALLS_FOOTPRINT, FD_SBPF_SYSCALLS_ALIGN))
     179             : 
     180           0 : #define FD_RUNTIME_VM_TRACE_EVENT_MAX      (128UL<<20)
     181           0 : #define FD_RUNTIME_VM_TRACE_EVENT_DATA_MAX (2048UL)
     182           0 : #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() ))
     183             : 
     184          24 : #define FD_RUNTIME_MISC_FOOTPRINT (FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT)
     185           0 : #define FD_SOLFUZZ_MISC_FOOTPRINT (FD_RUNTIME_SYSCALL_TABLE_FOOTPRINT + FD_RUNTIME_VM_TRACE_FOOTPRINT)
     186             : 
     187             : /* Now finally, we bound out the footprint of transaction execution. */
     188             : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(account_lock_limit, direct_mapping)                                         \
     189          24 :                                                   (FD_RUNTIME_BORROWED_ACCOUNT_FOOTPRINT                                     + \
     190          24 :                                                    FD_RUNTIME_INPUT_REGION_TXN_FOOTPRINT(account_lock_limit, direct_mapping) + \
     191          24 :                                                    FD_RUNTIME_BINCODE_AND_NATIVE_FOOTPRINT                                   + \
     192          24 :                                                    FD_RUNTIME_MISC_FOOTPRINT)
     193             : 
     194             : /* Convenience macros for common use cases.
     195             : 
     196             :    TODO: If account lock limits are increased to 128, this macro will need to be updated. */
     197           0 : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_FUZZ    FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(64UL, 0) + FD_SOLFUZZ_MISC_FOOTPRINT
     198          24 : #define FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_DEFAULT FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT(64UL, 0)
     199             : 
     200             : /* Helpers for runtime public frame management. */
     201             : 
     202             : /* Helpers for runtime spad frame management. */
     203             : struct fd_runtime_spad_verify_handle_private {
     204             :   fd_spad_t *         spad;
     205             :   fd_exec_txn_ctx_t * txn_ctx;
     206             : };
     207             : typedef struct fd_runtime_spad_verify_handle_private fd_runtime_spad_verify_handle_private_t;
     208             : 
     209             : static inline void
     210           0 : fd_runtime_spad_private_frame_end( fd_runtime_spad_verify_handle_private_t * _spad_handle ) {
     211             :   /* fd_spad_verify() returns 0 if everything looks good, and non-zero
     212             :      otherwise.
     213             : 
     214             :      Since the fast spad alloc API doesn't check for or indicate an OOM
     215             :      situation and is going to happily permit an OOB alloc, we need
     216             :      some way of detecting that. Moreover, we would also like to detect
     217             :      unbalanced frame push/pop or usage of more frames than allowed.
     218             :      While surrounding the spad with guard regions will help detect the
     219             :      former, it won't necessarily catch the latter.
     220             : 
     221             :      On compliant transactions, fd_spad_verify() isn't all that
     222             :      expensive.  Nonetheless, We invoke fd_spad_verify() only at the
     223             :      peak of memory usage, and not gratuitously everywhere. One peak
     224             :      would be right before we do the most deeply nested spad frame pop.
     225             :      However, we do pops through compiler-inserted cleanup functions
     226             :      that take only a single pointer, so we define this helper function
     227             :      to access the needed context info.  The end result is that we do
     228             :      super fast spad calls everywhere in the runtime, and every now and
     229             :      then we invoke verify to check things. */
     230             :   /* -1UL because spad pop is called after instr stack pop. */
     231           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 ) ) ) {
     232           0 :     uchar const * txn_signature = (uchar const *)fd_txn_get_signatures( TXN( &_spad_handle->txn_ctx->txn ), _spad_handle->txn_ctx->txn.payload );
     233           0 :     FD_BASE58_ENCODE_64_BYTES( txn_signature, sig );
     234           0 :     FD_LOG_ERR(( "spad corrupted or overflown on transaction %s", sig ));
     235           0 :   }
     236           0 :   fd_spad_pop( _spad_handle->spad );
     237           0 : }
     238             : 
     239           0 : #define FD_RUNTIME_TXN_SPAD_FRAME_BEGIN(_spad, _txn_ctx) do {                                                        \
     240           0 :   fd_runtime_spad_verify_handle_private_t _spad_handle __attribute__((cleanup(fd_runtime_spad_private_frame_end))) = \
     241           0 :     (fd_runtime_spad_verify_handle_private_t) { .spad = _spad, .txn_ctx = _txn_ctx };                                \
     242           0 :   fd_spad_push( _spad_handle.spad );                                                                                 \
     243           0 :   do
     244             : 
     245           0 : #define FD_RUNTIME_TXN_SPAD_FRAME_END while(0); } while(0)
     246             : 
     247             : FD_PROTOTYPES_BEGIN
     248             : 
     249             : /* Runtime Helpers ************************************************************/
     250             : 
     251             : /*
     252             :    Returns 0 on success, and non zero otherwise.  On failure, the
     253             :    out values will not be modified.
     254             :  */
     255             : int
     256             : fd_runtime_compute_max_tick_height( ulong   ticks_per_slot,
     257             :                                     ulong   slot,
     258             :                                     ulong * out_max_tick_height /* out */ );
     259             : 
     260             : void
     261             : fd_runtime_update_leaders( fd_bank_t * bank,
     262             :                            fd_spad_t * runtime_spad );
     263             : 
     264             : /* TODO: Invoked by fd_executor: layering violation. Rent logic is deprecated
     265             :    and will be torn out entirely very soon. */
     266             : ulong
     267             : fd_runtime_collect_rent_from_account( fd_epoch_schedule_t const * schedule,
     268             :                                       fd_rent_t const *           rent,
     269             :                                       double                      slots_per_year,
     270             :                                       fd_txn_account_t *          acc,
     271             :                                       ulong                       epoch );
     272             : 
     273             : void
     274             : fd_runtime_update_slots_per_epoch( fd_bank_t * bank,
     275             :                                    ulong       slots_per_epoch );
     276             : 
     277             : /* Block Level Execution Prep/Finalize ****************************************/
     278             : 
     279             : #define FD_BLOCK_OK                          (0UL)
     280             : #define FD_BLOCK_ERR_INCOMPLETE              (1UL)
     281             : #define FD_BLOCK_ERR_INVALID_ENTRY_HASH      (2UL)
     282             : #define FD_BLOCK_ERR_INVALID_LAST_TICK       (3UL)
     283             : #define FD_BLOCK_ERR_TOO_FEW_TICKS           (4UL)
     284             : #define FD_BLOCK_ERR_TOO_MANY_TICKS          (5UL)
     285             : #define FD_BLOCK_ERR_INVALID_TICK_HASH_COUNT (6UL)
     286             : #define FD_BLOCK_ERR_TRAILING_ENTRY          (7UL)
     287             : #define FD_BLOCK_ERR_DUPLICATE_BLOCK         (8UL)
     288             : 
     289             : /*
     290             :    https://github.com/anza-xyz/agave/blob/v2.1.0/ledger/src/blockstore_processor.rs#L1096
     291             :    This function assumes a full block.
     292             :    This needs to be called after epoch processing to get the up to date
     293             :    hashes_per_tick.
     294             : 
     295             :    Provide scratch memory >= the max size of a batch to use. This is because we can only
     296             :    assemble shreds by batch, so we iterate and assemble shreds by batch in this function
     297             :    without needing the caller to do so.
     298             :  */
     299             : // FD_FN_UNUSED ulong /* FIXME */
     300             : // fd_runtime_block_verify_ticks( fd_blockstore_t * blockstore,
     301             : //                                ulong             slot,
     302             : //                                uchar *           block_data_mem,
     303             : //                                ulong             block_data_sz,
     304             : //                                ulong             tick_height,
     305             : //                                ulong             max_tick_height,
     306             : //                                ulong             hashes_per_tick );
     307             : 
     308             : /* The following microblock-level functions are exposed and non-static due to also being used for fd_replay.
     309             :    The block-level equivalent functions, on the other hand, are mostly static as they are only used
     310             :    for offline replay */
     311             : 
     312             : /* extra fine-grained streaming tick verification */
     313             : // FD_FN_UNUSED int /* FIXME */
     314             : // fd_runtime_microblock_verify_ticks( fd_blockstore_t *           blockstore,
     315             : //                                     ulong                       slot,
     316             : //                                     fd_microblock_hdr_t const * hdr,
     317             : //                                     bool               slot_complete,
     318             : //                                     ulong              tick_height,
     319             : //                                     ulong              max_tick_height,
     320             : //                                     ulong              hashes_per_tick );
     321             : 
     322             : /*
     323             :    fd_runtime_microblock_verify_read_write_conflicts verifies that a
     324             :    list of txns (e.g., those in a microblock) do not have read-write
     325             :    or write-write conflits. FD_TXN_CONFLICT_MAP_MAX_NACCT defines a
     326             :    conservative estimation of the number of accounts touched by txns
     327             :    in one slot. Given the conservative estimation, the footprint of
     328             :    the account map (fd_conflict_detect_map) is about 2112MB. One can
     329             :    certainly use a better estimation leading to a smaller footprint.
     330             : 
     331             :    this function corresponds to try_lock_accounts in Agave which
     332             :    detects transaction conflicts:
     333             :    https://github.com/anza-xyz/agave/blob/v2.2.3/runtime/src/bank.rs
     334             :    #L3145
     335             : 
     336             :    Specifically, from the replay stage of Agave, the control flow is
     337             :    (1) replay_blockstore_into_bank: https://github.com/anza-xyz/agave/
     338             :    blob/v2.2.3/core/src/replay_stage.rs#L2232
     339             :    (2) confirm_slot: https://github.com/anza-xyz/agave/blob/v2.2.3/
     340             :    ledger/src/blockstore_processor.rs#L1561
     341             :    (3) confirm_slot_entries: https://github.com/anza-xyz/agave/blob/
     342             :    v2.2.3/ledger/src/blockstore_processor.rs#L1609
     343             :    (4) process_entries: https://github.com/anza-xyz/agave/blob/v2.2.3/
     344             :    ledger/src/blockstore_processor.rs#L704
     345             :    (5) queue_batches_with_lock_retry: https://github.com/anza-xyz/agave/
     346             :    blob/v2.2.3/ledger/src/blockstore_processor.rs#L789
     347             :    (6) bank.try_lock_accounts is called in queue_batches_with_lock_retry
     348             :    (7) this try_lock_accounts eventually calls another try_lock_accounts,
     349             :        (see https://github.com/anza-xyz/agave/blob/v2.2.3/accounts-db/src
     350             :        /account_locks.rs#L24), which acquires the locks and returns
     351             :        TransactionError::AccountInUse if r-w or w-w conflict is detected
     352             :    (8) when calling try_lock_accounts, function accounts_with_is_writable
     353             :    is used to decide whether an account is writable (see https://github.
     354             :    com/anza-xyz/agave/blob/v2.2.3/accounts-db/src/accounts.rs#L605) which
     355             :    internally calls the is_writable function depending on whether the txn
     356             :    is legacy or V0:
     357             : 
     358             :    is_writable for legacy: https://github.com/anza-xyz/solana-sdk/blob/
     359             :    message%40v2.2.1/message/src/sanitized.rs#L75
     360             : 
     361             :    is_writable for V0: https://github.com/anza-xyz/solana-sdk/blob/
     362             :    message%40v2.2.1/message/src/versions/v0/loaded.rs#L152
     363             : 
     364             :    In both cases, Agave does the following check in addition to whether
     365             :    an account has been specified as writable in the transaction message
     366             :    (https://github.com/anza-xyz/solana-sdk/blob/message%40v2.2.1/message
     367             :    /src/versions/v0/loaded.rs#L146). This additional check is handled by
     368             :    function fd_txn_account_is_writable_idx_flat in our code.
     369             : 
     370             :    txns is an array containing txn_cnt transactions in fd_txn_p_t type;
     371             :    acct_map is used to detect conflicts and acct_arr is used to clear the
     372             :    map before the function returns; funk and funk_txn are used to read
     373             :    Solana accounts for address lookup tables; slot and slot_hashes are
     374             :    needed for checking certain bounds in the address lookup table system
     375             :    program; features is needed in fd_txn_account_is_writable_idx_flat to
     376             :    decide whether a writable account is demoted to read-only.
     377             : 
     378             :    If an error occurs in runtime, the function returns the runtime error.
     379             :    If there's no conflict, the return value is FD_RUNTIME_EXECUTE_SUCCESS
     380             :    and out_conflict_detected will be 0. If there's a conflict, the return
     381             :    value is FD_RUNTIME_TXN_ERR_ACCOUNT_IN_USE and out_conflict_detected
     382             :    will be 1 (read-write) or 2 (write-write), and out_conflict_addr_opt,
     383             :    if not NULL, will hold the account address causing the conflict.
     384             :  */
     385             : struct fd_conflict_detect_ele {
     386             :   fd_acct_addr_t key;
     387             :   uchar          writable;
     388             : };
     389             : typedef struct fd_conflict_detect_ele fd_conflict_detect_ele_t;
     390         426 : #define FD_TXN_CONFLICT_MAP_SEED        (0UL)
     391             : #define FD_TXN_CONFLICT_MAP_MAX_NACCT   (FD_SHRED_DATA_PAYLOAD_MAX_PER_SLOT / FD_TXN_MIN_SERIALIZED_SZ * FD_TXN_ACCT_ADDR_MAX)
     392             : 
     393             : 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}};
     394             : #define MAP_NAME              fd_conflict_detect_map
     395         546 : #define MAP_KEY_T             fd_acct_addr_t
     396         432 : #define MAP_T                 fd_conflict_detect_ele_t
     397         426 : #define MAP_HASH_T            ulong
     398     3145848 : #define MAP_KEY_NULL          (fd_acct_addr_null)
     399         306 : #define MAP_KEY_EQUAL(k0,k1)  (0==memcmp((k0).b,(k1).b,32))
     400         426 : #define MAP_KEY_HASH(key)     fd_hash( FD_TXN_CONFLICT_MAP_SEED, key.b, 32 )
     401         876 : #define MAP_KEY_INVAL(k)      (0==memcmp(&fd_acct_addr_null, (k).b, 32))
     402             : #define MAP_KEY_EQUAL_IS_SLOW 0
     403             : #define MAP_MEMOIZE           0
     404             : 
     405             : #include "../../util/tmpl/fd_map_dynamic.c"
     406             : 
     407         270 : #define FD_RUNTIME_NO_CONFLICT_DETECTED          0
     408           6 : #define FD_RUNTIME_READ_WRITE_CONFLICT_DETECTED  1
     409           9 : #define FD_RUNTIME_WRITE_WRITE_CONFLICT_DETECTED 2
     410             : 
     411             : int
     412             : fd_runtime_microblock_verify_read_write_conflicts( fd_txn_p_t *               txns,
     413             :                                                    ulong                      txn_cnt,
     414             :                                                    fd_conflict_detect_ele_t * acct_map,
     415             :                                                    fd_acct_addr_t *           acct_arr,
     416             :                                                    fd_funk_t *                funk,
     417             :                                                    fd_funk_txn_xid_t const *  xid,
     418             :                                                    ulong                      slot,
     419             :                                                    fd_slot_hash_t *           slot_hashes,
     420             :                                                    fd_features_t *            features,
     421             :                                                    int *                      out_conflict_detected,
     422             :                                                    fd_acct_addr_t *           out_conflict_addr_opt );
     423             : 
     424             : /* Load the accounts in the address lookup tables of txn into out_accts_alt */
     425             : int
     426             : fd_runtime_load_txn_address_lookup_tables(
     427             :     fd_txn_t const *          txn,
     428             :     uchar const *             payload,
     429             :     fd_funk_t *               funk,
     430             :     fd_funk_txn_xid_t const * xid,
     431             :     ulong                     slot,
     432             :     fd_slot_hash_t const *    hashes, /* deque */
     433             :     fd_acct_addr_t *          out_accts_alt
     434             : );
     435             : 
     436             : int
     437             : fd_runtime_block_execute_prepare( fd_bank_t *               bank,
     438             :                                   fd_funk_t *               funk,
     439             :                                   fd_funk_txn_xid_t const * xid,
     440             :                                   fd_capture_ctx_t *        capture_ctx,
     441             :                                   fd_spad_t *               runtime_spad );
     442             : 
     443             : void
     444             : fd_runtime_block_execute_finalize( fd_bank_t *               bank,
     445             :                                    fd_funk_t *               funk,
     446             :                                    fd_funk_txn_xid_t const * xid,
     447             :                                    fd_capture_ctx_t *        capture_ctx,
     448             :                                    int                       silent );
     449             : 
     450             : /* Transaction Level Execution Management *************************************/
     451             : 
     452             : int
     453             : fd_runtime_pre_execute_check( fd_exec_txn_ctx_t * txn_ctx );
     454             : 
     455             : /* fd_runtime_prepare_and_execute_txn is the main entrypoint from the
     456             :    executor tile. It is responsible for preparing and executing a single
     457             :    transaction. */
     458             : 
     459             : int
     460             : fd_runtime_prepare_and_execute_txn( fd_banks_t *        banks,
     461             :                                     ulong               bank_idx,
     462             :                                     fd_exec_txn_ctx_t * txn_ctx,
     463             :                                     fd_txn_p_t *        txn,
     464             :                                     fd_spad_t *         exec_spad,
     465             :                                     fd_capture_ctx_t *  capture_ctx );
     466             : 
     467             : void
     468             : fd_runtime_finalize_txn( fd_funk_t *               funk,
     469             :                          fd_txncache_t *           txncache,
     470             :                          fd_funk_txn_xid_t const * xid,
     471             :                          fd_exec_txn_ctx_t *       txn_ctx,
     472             :                          fd_bank_t *               bank,
     473             :                          fd_capture_ctx_t *        capture_ctx );
     474             : 
     475             : /* Epoch Boundary *************************************************************/
     476             : 
     477             : /*
     478             :    This is roughly Agave's process_new_epoch() which gets called from
     479             :    new_from_parent() for every slot.
     480             :    https://github.com/anza-xyz/agave/blob/v1.18.26/runtime/src/bank.rs#L1483
     481             :    This needs to be called after funk_txn_prepare() because the accounts
     482             :    that we modify when processing a new epoch need to be hashed into
     483             :    the bank hash.
     484             :  */
     485             : void
     486             : fd_runtime_block_pre_execute_process_new_epoch( fd_banks_t *              banks,
     487             :                                                 fd_bank_t *               bank,
     488             :                                                 fd_funk_t *               funk,
     489             :                                                 fd_funk_txn_xid_t const * xid,
     490             :                                                 fd_capture_ctx_t *        capture_ctx,
     491             :                                                 fd_spad_t *               runtime_spad,
     492             :                                                 int *                     is_epoch_boundary );
     493             : 
     494             : /* `fd_runtime_update_program_cache()` is responsible for updating the
     495             :    program cache with any programs referenced in the current
     496             :    transaction. See fd_program_cache.h for more details.
     497             : 
     498             :    Note that ALUTs must be resolved because programs referenced in ALUTs
     499             :    can be invoked via CPI.
     500             : 
     501             :    TODO: We need to remove the ALUT resolution from this function
     502             :    because it is redundant (ALUTs get resolved again in the exec tile). */
     503             : void
     504             : fd_runtime_update_program_cache( fd_bank_t *               bank,
     505             :                                  fd_funk_t *               funk,
     506             :                                  fd_funk_txn_xid_t const * xid,
     507             :                                  fd_txn_p_t const *        txn_p,
     508             :                                  fd_spad_t *               runtime_spad );
     509             : 
     510             : /* Offline Replay *************************************************************/
     511             : 
     512             : void
     513             : fd_runtime_read_genesis( fd_banks_t *                       banks,
     514             :                          fd_bank_t *                        bank,
     515             :                          fd_funk_t *                        funk,
     516             :                          fd_funk_txn_xid_t const *          xid,
     517             :                          fd_capture_ctx_t *                 capture_ctx,
     518             :                          fd_hash_t const *                  genesis_hash,
     519             :                          fd_lthash_value_t const *          genesis_lthash,
     520             :                          fd_genesis_solana_global_t const * genesis_block,
     521             :                          fd_spad_t *                        runtime_spad );
     522             : 
     523             : 
     524             : /* Returns whether the specified epoch should use the new vote account
     525             :    keyed leader schedule (returns 1) or the old validator identity keyed
     526             :    leader schedule (returns 0). See SIMD-0180.
     527             :    This is the analogous of Agave's Bank::should_use_vote_keyed_leader_schedule():
     528             :    https://github.com/anza-xyz/agave/blob/v2.3.1/runtime/src/bank.rs#L6148 */
     529             : int
     530             : fd_runtime_should_use_vote_keyed_leader_schedule( fd_bank_t * bank );
     531             : 
     532             : FD_PROTOTYPES_END
     533             : 
     534             : #endif /* HEADER_fd_src_flamenco_runtime_fd_runtime_h */

Generated by: LCOV version 1.14