LCOV - code coverage report
Current view: top level - flamenco/runtime/program - fd_bpf_loader_serialization.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 342 433 79.0 %
Date: 2026-05-15 07:18:56 Functions: 7 8 87.5 %

          Line data    Source code
       1             : #include "fd_bpf_loader_serialization.h"
       2             : #include "../fd_borrowed_account.h"
       3             : #include "../fd_runtime.h"
       4             : #include "../../vm/fd_vm_base.h"
       5             : 
       6             : /* This file is responsible for serializing and deserializing
       7             :    the input region of the BPF virtual machine. The input region contains
       8             :    instruction information, account metadata, and account data. The high level
       9             :    format is as follows:
      10             : 
      11             :    [ account 1 metadata, account 1 data, account 2 metadata, account 2 data, ...,
      12             :      account N metadata, account N data, instruction info. ]
      13             : 
      14             :   This format by no means comprehensive, but it should give an idea of how
      15             :   the input region is laid out. When direct mapping is not enabled, the input
      16             :   region is stored as a single contiguous buffer. This buffer in the host
      17             :   address space is then mapped to the VM virtual address space (the range
      18             :   starting with 0x400...). This means to serialize into the input region, we
      19             :   need to copy in the account metadata and account data into the buffer for
      20             :   each account. Everything must get copied out after execution is complete.
      21             :   A consequence of this is that a memcpy for the account data is required
      22             :   for each serialize and deserialize operation: this can potentially become
      23             :   expensive if there are many accounts and many nested CPI calls. Also, the
      24             :   entire memory region is treated as writable even though many accounts are
      25             :   read-only. This means that for all read-only accounts, a memcmp must be done
      26             :   while deserializing to make sure that the account (meta)data has not changed.
      27             : 
      28             :   Direct mapping offers a solution to this by introducing a more sophisticated
      29             :   memory translation protocol. Now the account data is not copied into a single
      30             :   contiguous buffer, but instead a borrowed account's data is directly mapped
      31             :   into the VM's virtual address space. The host memory for the input region is
      32             :   now represented by a list of fragmented memory regions. These sub regions
      33             :   also have different write permissions. This should solve the problem of
      34             :   having to memcpy/memcmp account data regions (which can be up to 10MiB each).
      35             :   There is some nuance to this, as the account data can be resized. This means
      36             :   that memcpys for account data regions can't totally be avoided.
      37             : 
      38             :   SERIALIZATION BEHAVIOR
      39             :   ==========================================
      40             : 
      41             :   This implementation supports three distinct serialization modes based on two
      42             :   feature flags: virtual_address_space_adjustments and
      43             :   account_data_direct_mapping.
      44             : 
      45             :   MODE 1
      46             :   --------------------------------------
      47             :   virtual_address_space_adjustments = false
      48             :   account_data_direct_mapping       = false
      49             : 
      50             :   Memory Layout:
      51             :   - Single contiguous buffer in host memory
      52             :   - Buffer contains: [metadata1, data1, realloc_buffer1, metadata2, data2,
      53             :     realloc_buffer2, ..., metadataN, dataN, realloc_bufferN, instruction_info]
      54             :   - Each account gets: original data + MAX_PERMITTED_DATA_INCREASE (10KiB)
      55             :   - Padding added to maintain 16-byte alignment between accounts
      56             :   - Entire buffer is writable
      57             : 
      58             :   Memory Regions:
      59             :   - The entire input region buffer is mapped as one contiguous VM address
      60             :     space region
      61             : 
      62             :   Serialization Process:
      63             :   - Account data is memcpy'd into the buffer
      64             :   - 10KiB realloc buffer is zeroed out and appended after each account's data
      65             :   - Alignment padding is zeroed and added after realloc buffer
      66             : 
      67             :   Deserialization Process:
      68             :   - Account data must be memcpy'd back from buffer to borrowed account
      69             :   - For writable accounts: always copy data back
      70             :   - For read-only accounts: memcmp to verify data unchanged, error if modified
      71             :   - Account resizing allowed if account permissions permit it
      72             : 
      73             :   MODE 2
      74             :   -------------------------------------------
      75             :   virtual_address_space_adjustments = true
      76             :   account_data_direct_mapping       = false
      77             : 
      78             :   Memory Layout:
      79             :   - Still uses a single contiguous buffer, but organized into fragmented
      80             :     regions.
      81             :   - Each account now has separate regions for metadata and data+realloc.
      82             :   - Buffer contains: [metadata1, data1+realloc1, metadata2, data2+realloc2, ...,
      83             :     metadataN, dataN+reallocN, instruction_info].
      84             :   - Each metadata region and data region tracked separately in
      85             :     input_mem_regions.
      86             : 
      87             :   Memory Regions:
      88             :   - For each account:
      89             :     * Region 0: Account metadata (writable)
      90             :     * Region 1: Account data + realloc space (writable if account is writable)
      91             :   - If the account is owned by the deprecated loader, no realloc region is
      92             :     created as the deprecated loader does not support resizing accounts.
      93             : 
      94             :   Serialization:
      95             :   - Account metadata serialized first, added as a memory region.
      96             :   - Account data memcpy'd into buffer - not directly mapped.
      97             :   - 10KiB realloc buffer zeroed and appended (not direct mapped).
      98             :   - Data region created pointing to copied data in buffer.
      99             : 
     100             :   MODE 3: Direct Mapping (requires virtual_address_space_adjustments)
     101             :   -----------------------------------------------
     102             :   virtual_address_space_adjustments = true
     103             :   account_data_direct_mapping       = true
     104             : 
     105             :   This is very similar to virtual_address_space_adjustments, but account
     106             :   data is NOT copied into the input region buffer.
     107             : 
     108             :   Instead, the data region points directly to the staging area for the
     109             :   account in the transaction account's data. This staging area has enough
     110             :   space to hold the account data and the realloc buffer. Changes to this
     111             :   staging area will be written back to the account database in transaction
     112             :   finalization.
     113             :  */
     114             : 
     115             : /* Add a new memory region to represent the input region. All of the memory
     116             :    regions here have sorted virtual addresses. These regions may or may not
     117             :    correspond to an account's data region. If it corresponds to metadata,
     118             :    the pubkey for the region will be NULL. */
     119             : static void
     120             : new_input_mem_region( fd_vm_input_region_t * input_mem_regions,
     121             :                       uint *                 input_mem_regions_cnt,
     122             :                       const uchar *          buffer,
     123             :                       ulong                  region_sz,
     124             :                       ulong                  address_space_reserved,
     125             :                       uchar                  is_writable,
     126        8004 :                       ulong                  acc_region_meta_idx ) {
     127             : 
     128             :   /* The start vaddr of the new region should be equal to start of the previous
     129             :      region added to the address space reserved for the region. */
     130        8004 :   ulong vaddr_offset = *input_mem_regions_cnt==0UL ? 0UL : input_mem_regions[ *input_mem_regions_cnt-1U ].vaddr_offset +
     131        5040 :                                                            input_mem_regions[ *input_mem_regions_cnt-1U ].address_space_reserved;
     132        8004 :   input_mem_regions[ *input_mem_regions_cnt ].is_writable            = is_writable;
     133        8004 :   input_mem_regions[ *input_mem_regions_cnt ].haddr                  = (ulong)buffer;
     134        8004 :   input_mem_regions[ *input_mem_regions_cnt ].region_sz              = (uint)region_sz;
     135        8004 :   input_mem_regions[ *input_mem_regions_cnt ].address_space_reserved = address_space_reserved;
     136        8004 :   input_mem_regions[ *input_mem_regions_cnt ].vaddr_offset           = vaddr_offset;
     137        8004 :   input_mem_regions[ *input_mem_regions_cnt ].acc_region_meta_idx    = acc_region_meta_idx;
     138        8004 :   (*input_mem_regions_cnt)++;
     139        8004 : }
     140             : 
     141             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L128-L190 */
     142             : /* This function handles casing for direct mapping being enabled as well as if
     143             :    the alignment is being stored. In the case where direct mapping is not
     144             :    enabled, we copy in the account data and a 10KiB buffer into the input region.
     145             :    These both go into the same memory buffer. However, when direct mapping is
     146             :    enabled, the account data and resizing buffers are represented by two
     147             :    different memory regions. In both cases, padding is used to maintain 8 byte
     148             :    alignment. If alignment is not required, then a resizing buffer is not used
     149             :    as the deprecated loader doesn't allow for resizing accounts. */
     150             : static ulong
     151             : write_account( fd_borrowed_account_t *   account,
     152             :                uchar                     instr_acc_idx,
     153             :                uchar * *                 serialized_params,
     154             :                uchar * *                 serialized_params_start,
     155             :                fd_vm_input_region_t *    input_mem_regions,
     156             :                uint *                    input_mem_regions_cnt,
     157             :                fd_vm_acc_region_meta_t * acc_region_metas,
     158             :                int                       is_loader_v1,
     159             :                int                       virtual_address_space_adjustments,
     160        4599 :                int                       direct_mapping ) {
     161             : 
     162        4599 :   uchar const * data = account ? fd_borrowed_account_get_data( account )     : NULL;
     163        4599 :   ulong         dlen = account ? fd_borrowed_account_get_data_len( account ) : 0UL;
     164             : 
     165        4599 :   acc_region_metas[instr_acc_idx].original_data_len = dlen;
     166        4599 :   acc_region_metas[instr_acc_idx].meta              = account->meta;
     167             : 
     168             :   /* Legacy behavior: no virtual_address_space_adjustments (also implies no direct mapping)
     169             :      https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L132-L142 */
     170        4599 :   if( !virtual_address_space_adjustments ) {
     171             :     /* Copy the account data into input region buffer */
     172        2067 :     fd_memcpy( *serialized_params, data, dlen );
     173        2067 :     *serialized_params += dlen;
     174             : 
     175        2067 :     if( FD_LIKELY( !is_loader_v1 ) ) {
     176             :       /* Zero out padding bytes and max permitted data increase */
     177        2007 :       ulong align_offset = fd_ulong_align_up( dlen, FD_BPF_ALIGN_OF_U128 ) - dlen;
     178        2007 :       fd_memset( *serialized_params, 0, MAX_PERMITTED_DATA_INCREASE + align_offset );
     179        2007 :       *serialized_params += MAX_PERMITTED_DATA_INCREASE + align_offset;
     180        2007 :     }
     181        2067 :     acc_region_metas[instr_acc_idx].region_idx = UINT_MAX;
     182        2532 :   } else { /* virtual_address_space_adjustments == true */
     183             : 
     184             :     /* Set up account region metadata */
     185        2532 :     acc_region_metas[instr_acc_idx].region_idx = *input_mem_regions_cnt;
     186             : 
     187             :     /* First, push on the region for the metadata that has just been serialized.
     188             :        This function will push the metadata in the serialized_params from
     189             :        serialized_params_start to serialized_params as a region to the input
     190             :        memory regions array.
     191             : 
     192             :        https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L143 */
     193        2532 :     ulong region_sz = (ulong)(*serialized_params) - (ulong)(*serialized_params_start);
     194        2532 :     new_input_mem_region( input_mem_regions, input_mem_regions_cnt, *serialized_params_start, region_sz, region_sz, 1U, ULONG_MAX );
     195             : 
     196             :     /* If direct mapping isn't enabled, then copy the account data in directly
     197             :        https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L145-L151 */
     198        2532 :     if( !direct_mapping ) {
     199        1044 :       fd_memcpy( *serialized_params, data, dlen );
     200        1044 :       *serialized_params += dlen;
     201        1044 :       if( FD_LIKELY( !is_loader_v1 ) ) {
     202         984 :         fd_memset( *serialized_params, 0, MAX_PERMITTED_DATA_INCREASE );
     203         984 :         *serialized_params += MAX_PERMITTED_DATA_INCREASE;
     204         984 :       }
     205        1044 :     }
     206             : 
     207             :     /* Calculate address space reserved for account (data + realloc space)
     208             :        https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L152-L159 */
     209        2532 :     ulong address_space_reserved = !is_loader_v1 ?
     210        2412 :       fd_ulong_sat_add( dlen, MAX_PERMITTED_DATA_INCREASE ) : dlen;
     211             : 
     212             :     /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L160-L170 */
     213        2532 :     if( address_space_reserved > 0 ) {
     214        2508 :       int err = 0;
     215        2508 :       uchar is_writable = !!(fd_borrowed_account_can_data_be_changed( account, &err ) && !err);
     216             : 
     217        2508 :       if( !direct_mapping ) {
     218             :         /* Create region pointing to the copied data in buffer
     219             :            https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L161-L165 */
     220        1032 :         uchar * data_start = *serialized_params - address_space_reserved;
     221        1032 :         new_input_mem_region( input_mem_regions, input_mem_regions_cnt, data_start, dlen, address_space_reserved, is_writable, instr_acc_idx );
     222        1476 :       } else {
     223             :         /* Direct mapping: create region pointing directly to account data */
     224        1476 :         new_input_mem_region( input_mem_regions, input_mem_regions_cnt, data, dlen, address_space_reserved, is_writable, instr_acc_idx );
     225        1476 :       }
     226        2508 :     }
     227             : 
     228        2532 :     *serialized_params_start = *serialized_params;
     229             : 
     230             :     /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L171-L187 */
     231        2532 :     if( FD_LIKELY( !is_loader_v1 ) ) {
     232        2412 :       ulong align_offset = fd_ulong_align_up( dlen, FD_BPF_ALIGN_OF_U128 ) - dlen;
     233        2412 :       if( !direct_mapping ) {
     234             :         /* If direct mapping is not enabled, we do not align the start of each
     235             :            region metadata to FD_BPF_ALIGN_OF_U128, but we do align the start
     236             :            of the actual contents of the metadata region.
     237             : 
     238             :            This follows Agave's logic
     239             :            https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L174-L177 */
     240         984 :         fd_memset( *serialized_params, 0, align_offset );
     241         984 :         *serialized_params += align_offset;
     242        1428 :       } else {
     243             :         /* If direct mapping is enabled, we align the start of each region
     244             :            metadata to FD_BPF_ALIGN_OF_U128. */
     245        1428 :         fd_memset( *serialized_params, 0, FD_BPF_ALIGN_OF_U128 );
     246        1428 :         *serialized_params       += FD_BPF_ALIGN_OF_U128;
     247        1428 :         *serialized_params_start += fd_ulong_sat_sub( FD_BPF_ALIGN_OF_U128, align_offset );
     248        1428 :       }
     249        2412 :     }
     250             : 
     251        2532 :     return region_sz + address_space_reserved;
     252        2532 :   }
     253             : 
     254        2067 :   return 0UL;
     255        4599 : }
     256             : 
     257             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L473 */
     258             : static int
     259             : fd_bpf_loader_input_serialize_for_abiv1( fd_exec_instr_ctx_t *     ctx,
     260             :                                          ulong *                   pre_lens,
     261             :                                          fd_vm_input_region_t *    input_mem_regions,
     262             :                                          uint *                    input_mem_regions_cnt,
     263             :                                          fd_vm_acc_region_meta_t * acc_region_metas,
     264             :                                          int                       virtual_address_space_adjustments,
     265             :                                          int                       direct_mapping,
     266             :                                          int                       direct_account_pointers_in_program_input,
     267             :                                          ulong *                   instr_data_offset,
     268        2856 :                                          ulong *                   serialized_bytes_written ) {
     269        2856 :   fd_pubkey_t * txn_accs = ctx->txn_out->accounts.keys;
     270             : 
     271             :   /* Transaction sanitisation limits the number of instruction accounts to
     272             :      FD_TXN_ACCT_ADDR_MAX. */
     273        2856 :   uchar  acc_idx_seen[ FD_TXN_ACCT_ADDR_MAX ] = {0};
     274        2856 :   ushort dup_acc_idx[ FD_TXN_ACCT_ADDR_MAX ]  = {0};
     275             : 
     276             :   /* 16-byte aligned buffer from runtime:
     277             :      https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L61 */
     278        2856 :   uchar * serialized_params            = ctx->runtime->bpf_loader_serialization.serialization_mem[ ctx->runtime->instr.stack_sz-1UL ];
     279        2856 :   uchar * serialized_params_start      = serialized_params;
     280        2856 :   uchar * curr_serialized_params_start = serialized_params;
     281        2856 :   ulong   curr_region_vaddr            = 0UL;
     282             : 
     283             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L539 */
     284        2856 :   FD_STORE( ulong, serialized_params, ctx->instr->acct_cnt );
     285        2856 :   serialized_params += sizeof(ulong);
     286             : 
     287             :   /* Iterate over accounts in the instruction to populate input region.
     288             :      https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L540-L570 */
     289        9216 :   for( ushort i=0; i<ctx->instr->acct_cnt; i++ ) {
     290        6360 :     uchar         acc_idx = (uchar)ctx->instr->accounts[i].index_in_transaction;
     291        6360 :     fd_pubkey_t * acc     = &txn_accs[acc_idx];
     292             : 
     293        6360 :     if( FD_UNLIKELY( acc_idx_seen[acc_idx] && dup_acc_idx[acc_idx] != i ) ) {
     294             :       /* Duplicate. Store 8 byte buffer to maintain alignment but store the
     295             :          account index in the first byte.
     296             : 
     297             :          https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L564-L568 */
     298        1941 :       FD_STORE( ulong, serialized_params, 0UL );
     299        1941 :       FD_STORE( uchar, serialized_params, (uchar)dup_acc_idx[acc_idx] );
     300        1941 :       serialized_params += sizeof(ulong);
     301             : 
     302             :       /* Clone the account metadata from the original account
     303             :          https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L372 */
     304        1941 :       acc_region_metas[i] = acc_region_metas[dup_acc_idx[acc_idx]];
     305        4419 :     } else {
     306        4419 :       acc_idx_seen[acc_idx] = 1;
     307        4419 :       dup_acc_idx[acc_idx]  = i;
     308             : 
     309        4419 :       acc_region_metas[i].vm_addr = FD_VM_MEM_MAP_INPUT_REGION_START + curr_region_vaddr +
     310        4419 :         (ulong)(serialized_params - curr_serialized_params_start);
     311             : 
     312             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L376 */
     313        4419 :       FD_STORE( uchar, serialized_params, FD_NON_DUP_MARKER );
     314        4419 :       serialized_params += sizeof(uchar);
     315             : 
     316             :       /* Borrow the account
     317             :          https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L245-L258 */
     318        4419 :       fd_guarded_borrowed_account_t view_acc = {0};
     319        4419 :       int err = fd_exec_instr_ctx_try_borrow_instr_account( ctx, i, &view_acc );
     320        4419 :       if( FD_UNLIKELY( err ) ) {
     321           0 :         return err;
     322           0 :       }
     323             : 
     324             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L542 */
     325        4419 :       fd_account_meta_t const * metadata = fd_borrowed_account_get_acc_meta( &view_acc );
     326             : 
     327             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L544 */
     328        4419 :       uchar is_signer = (uchar)fd_instr_acc_is_signer_idx( ctx->instr, (uchar)i, NULL );
     329        4419 :       FD_STORE( uchar, serialized_params, is_signer );
     330        4419 :       serialized_params += sizeof(uchar);
     331             : 
     332             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L545 */
     333        4419 :       uchar is_writable = (uchar)fd_instr_acc_is_writable_idx( ctx->instr, (uchar)i );
     334        4419 :       FD_STORE( uchar, serialized_params, is_writable );
     335        4419 :       serialized_params += sizeof(uchar);
     336             : 
     337             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L546-L547 */
     338        4419 :       uchar is_executable = (uchar)metadata->executable;
     339        4419 :       FD_STORE( uchar, serialized_params, is_executable );
     340        4419 :       serialized_params += sizeof(uchar);
     341             : 
     342             :       /* The original data len field is intentionally NOT populated. */
     343             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L548 */
     344        4419 :       uint padding_0 = 0U;
     345        4419 :       FD_STORE( uint, serialized_params, padding_0 );
     346        4419 :       serialized_params += sizeof(uint);
     347             : 
     348             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L549 */
     349        4419 :       fd_pubkey_t key = *acc;
     350        4419 :       acc_region_metas[i].vm_key_addr = FD_VM_MEM_MAP_INPUT_REGION_START + curr_region_vaddr +
     351        4419 :         (ulong)(serialized_params - curr_serialized_params_start);
     352        4419 :       FD_STORE( fd_pubkey_t, serialized_params, key );
     353        4419 :       serialized_params += sizeof(fd_pubkey_t);
     354             : 
     355             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L550 */
     356        4419 :       fd_pubkey_t owner = *(fd_pubkey_t *)&metadata->owner;
     357        4419 :       acc_region_metas[i].vm_owner_addr = FD_VM_MEM_MAP_INPUT_REGION_START + curr_region_vaddr +
     358        4419 :         (ulong)(serialized_params - curr_serialized_params_start);
     359        4419 :       FD_STORE( fd_pubkey_t, serialized_params, owner );
     360        4419 :       serialized_params += sizeof(fd_pubkey_t);
     361             : 
     362             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L551 */
     363        4419 :       ulong lamports = metadata->lamports;
     364        4419 :       acc_region_metas[i].vm_lamports_addr = FD_VM_MEM_MAP_INPUT_REGION_START + curr_region_vaddr +
     365        4419 :         (ulong)(serialized_params - curr_serialized_params_start);
     366        4419 :       FD_STORE( ulong, serialized_params, lamports );
     367        4419 :       serialized_params += sizeof(ulong);
     368             : 
     369        4419 :       ulong acc_data_len = metadata->dlen;
     370        4419 :       pre_lens[i] = acc_data_len;
     371             : 
     372             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L552 */
     373        4419 :       ulong data_len = acc_data_len;
     374        4419 :       FD_STORE( ulong, serialized_params, data_len );
     375        4419 :       serialized_params += sizeof(ulong);
     376             : 
     377             :       /* vm_data_addr: data is written immediately after the data_len field */
     378        4419 :       acc_region_metas[i].vm_data_addr = FD_VM_MEM_MAP_INPUT_REGION_START + curr_region_vaddr +
     379        4419 :         (ulong)(serialized_params - curr_serialized_params_start);
     380             : 
     381             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L553 */
     382        4419 :       write_account(
     383        4419 :         &view_acc,
     384        4419 :         (uchar)i,
     385        4419 :         &serialized_params,
     386        4419 :         &curr_serialized_params_start,
     387        4419 :         input_mem_regions,
     388        4419 :         input_mem_regions_cnt,
     389        4419 :         acc_region_metas,
     390        4419 :         0,
     391        4419 :         virtual_address_space_adjustments,
     392        4419 :         direct_mapping );
     393             : 
     394             :       /* write_account may have pushed a new region(s) */
     395        4419 :       curr_region_vaddr = *input_mem_regions_cnt == 0U ? 0UL :
     396        4419 :         input_mem_regions[*input_mem_regions_cnt-1U].vaddr_offset +
     397        2412 :         input_mem_regions[*input_mem_regions_cnt-1U].address_space_reserved;
     398             : 
     399             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L554-L555 */
     400        4419 :       FD_STORE( ulong, serialized_params, ULONG_MAX );
     401        4419 :       serialized_params += sizeof(ulong);
     402        4419 :     }
     403             : 
     404        6360 :   }
     405             : 
     406             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L571 */
     407        2856 :   ulong instr_data_len = ctx->instr->data_sz;
     408        2856 :   FD_STORE( ulong, serialized_params, instr_data_len );
     409        2856 :   serialized_params += sizeof(ulong);
     410             : 
     411             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L572 */
     412        2856 :   *instr_data_offset = FD_VM_MEM_MAP_INPUT_REGION_START + curr_region_vaddr +
     413        2856 :     (ulong)(serialized_params - curr_serialized_params_start);
     414             : 
     415             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L571 */
     416        2856 :   fd_memcpy( serialized_params, ctx->instr->data, instr_data_len );
     417        2856 :   serialized_params += instr_data_len;
     418             : 
     419             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L400 */
     420        2856 :   FD_STORE( fd_pubkey_t, serialized_params, txn_accs[ctx->instr->program_id] );
     421        2856 :   serialized_params += sizeof(fd_pubkey_t);
     422             : 
     423             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-rc.0/program-runtime/src/serialization.rs#L522-L529 */
     424        2856 :   if( direct_account_pointers_in_program_input ) {
     425         240 :     ulong cur_vaddr = FD_VM_MEM_MAP_INPUT_REGION_START + curr_region_vaddr +
     426         240 :       (ulong)(serialized_params - curr_serialized_params_start);
     427         240 :     ulong padding = FD_ULONG_ALIGN_UP( cur_vaddr, FD_BPF_ALIGN_OF_U128 ) - cur_vaddr;
     428         240 :     fd_memset( serialized_params, 0, padding );
     429         240 :     serialized_params += padding;
     430        2706 :     for( ushort i=0; i<ctx->instr->acct_cnt; i++ ) {
     431        2466 :       FD_STORE( ulong, serialized_params, acc_region_metas[i].vm_addr );
     432        2466 :       serialized_params += sizeof(ulong);
     433        2466 :     }
     434         240 :   }
     435             : 
     436             :   /* Write out the final region. */
     437        2856 :   ulong region_sz = (ulong)(serialized_params - curr_serialized_params_start);
     438        2856 :   new_input_mem_region( input_mem_regions, input_mem_regions_cnt, curr_serialized_params_start,
     439        2856 :                         region_sz, region_sz, 1U, ULONG_MAX );
     440             : 
     441        2856 :   *serialized_bytes_written = (ulong)(serialized_params - serialized_params_start);
     442        2856 :   return FD_EXECUTOR_INSTR_SUCCESS;
     443        2856 : }
     444             : 
     445             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L594-L681 */
     446             : static int
     447             : fd_bpf_loader_input_deserialize_for_abiv1( fd_exec_instr_ctx_t * ctx,
     448             :                                            ulong const *         pre_lens,
     449             :                                            uchar *               buffer,
     450             :                                            ulong FD_FN_UNUSED    buffer_sz,
     451             :                                            int                   virtual_address_space_adjustments,
     452        2373 :                                            int                   direct_mapping ) {
     453             :   /* TODO: An optimization would be to skip ahead through non-writable accounts */
     454             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L601 */
     455        2373 :   ulong start = 0UL;
     456             : 
     457        2373 :   uchar acc_idx_seen[256] = {0};
     458             : 
     459        2373 :   start += sizeof(ulong); // number of accounts
     460             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L602-L679 */
     461        5787 :   for( ushort i=0; i<ctx->instr->acct_cnt; i++ ) {
     462        3534 :     uchar acc_idx = (uchar)ctx->instr->accounts[i].index_in_transaction;
     463             : 
     464        3534 :     start++; // position
     465             : 
     466             :     /* get the borrowed account
     467             :        https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L612-L613 */
     468        3534 :     fd_guarded_borrowed_account_t view_acc = {0};
     469        3534 :     FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, i, &view_acc );
     470             : 
     471        3534 :     if( FD_UNLIKELY( acc_idx_seen[acc_idx] ) ) {
     472             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L610 */
     473         144 :       start += 7UL;
     474        3390 :     } else {
     475             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L614-L618 */
     476        3390 :       acc_idx_seen[acc_idx] = 1;
     477        3390 :       start += sizeof(uchar)        // is_signer
     478        3390 :              + sizeof(uchar)        // is_writable
     479        3390 :              + sizeof(uchar)        // executable
     480        3390 :              + sizeof(uint)         // original_data_len
     481        3390 :              + sizeof(fd_pubkey_t); // key
     482             : 
     483             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L619-L621 */
     484             : 
     485        3390 :       fd_pubkey_t * owner = (fd_pubkey_t *)(buffer+start);
     486        3390 :       start += sizeof(fd_pubkey_t); // owner
     487             : 
     488        3390 :       ulong lamports = FD_LOAD( ulong, buffer+start );
     489        3390 :       if( lamports!=fd_borrowed_account_get_lamports( &view_acc ) ) {
     490           0 :         int err = fd_borrowed_account_set_lamports( &view_acc, lamports );
     491           0 :         if( FD_UNLIKELY( err ) ) {
     492           0 :           return err;
     493           0 :         }
     494           0 :       }
     495        3390 :       start += sizeof(ulong); // lamports
     496             : 
     497        3390 :       ulong post_len = FD_LOAD( ulong, buffer+start );
     498        3390 :       start += sizeof(ulong); // data length
     499             : 
     500        3390 :       ulong pre_len = pre_lens[i];
     501        3390 :       ulong alignment_offset = fd_ulong_align_up( pre_len, FD_BPF_ALIGN_OF_U128 ) - pre_len;
     502             : 
     503        3390 :       uchar * post_data = buffer+start;
     504             : 
     505             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L640-L644 */
     506        3390 :       if( FD_UNLIKELY( fd_ulong_sat_sub( post_len, pre_len )>MAX_PERMITTED_DATA_INCREASE ||
     507        3390 :                        post_len>MAX_PERMITTED_DATA_LENGTH ) ) {
     508          96 :         return FD_EXECUTOR_INSTR_ERR_INVALID_REALLOC;
     509          96 :       }
     510             : 
     511        3294 :       int can_data_be_changed_err = 0;
     512        3294 :       if( !virtual_address_space_adjustments ) {
     513             :         /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L645-L655 */
     514             : 
     515             :         /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L646-L648 */
     516        1719 :         if( FD_UNLIKELY( start + post_len > buffer_sz ) ) {
     517           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     518           0 :         }
     519             : 
     520             :         /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L649-L654 */
     521        1719 :         int can_data_be_resized_err = 0;
     522        1719 :         if( fd_borrowed_account_can_data_be_resized( &view_acc, post_len, &can_data_be_resized_err ) &&
     523        1719 :             fd_borrowed_account_can_data_be_changed( &view_acc, &can_data_be_changed_err ) ) {
     524        1365 :           int set_data_err = fd_borrowed_account_set_data_from_slice( &view_acc, post_data, post_len );
     525        1365 :           if( FD_UNLIKELY( set_data_err ) ) {
     526           0 :             return set_data_err;
     527           0 :           }
     528        1365 :         } else {
     529         354 :           if( FD_UNLIKELY( fd_borrowed_account_get_data_len( &view_acc )!=post_len ||
     530         354 :                            memcmp( fd_borrowed_account_get_data( &view_acc ), post_data, post_len ) ) ) {
     531          24 :             return can_data_be_resized_err ? can_data_be_resized_err : can_data_be_changed_err;
     532          24 :           }
     533         354 :         }
     534             : 
     535        1719 :       } else if( !direct_mapping && fd_borrowed_account_can_data_be_changed( &view_acc, &can_data_be_changed_err ) ) {
     536             :         /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L657-L659 */
     537         624 :         if( FD_UNLIKELY( start + post_len > buffer_sz ) ) {
     538           0 :           return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     539           0 :         }
     540             : 
     541             :         /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L655-L661 */
     542         624 :         int set_data_err = fd_borrowed_account_set_data_from_slice( &view_acc, post_data, post_len );
     543         624 :         if( FD_UNLIKELY( set_data_err ) ) {
     544           0 :           return set_data_err;
     545           0 :         }
     546         951 :       } else if( fd_borrowed_account_get_data_len( &view_acc ) != post_len ) {
     547             :         /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L661-L663 */
     548         156 :         int set_data_length_err = fd_borrowed_account_set_data_length( &view_acc, post_len );
     549         156 :         if( FD_UNLIKELY( set_data_length_err ) ) {
     550           0 :           return set_data_length_err;
     551           0 :         }
     552         156 :       }
     553             : 
     554             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L664-L672 */
     555        3270 :       if( !( virtual_address_space_adjustments && direct_mapping ) ) {
     556        2475 :         start += fd_ulong_sat_add( MAX_PERMITTED_DATA_INCREASE, fd_ulong_sat_add( pre_len, alignment_offset ) );
     557        2475 :       } else {
     558         795 :         start += FD_BPF_ALIGN_OF_U128;
     559         795 :       }
     560             : 
     561             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L673 */
     562        3270 :       start += sizeof(ulong); // rent epoch
     563        3270 :       if( memcmp( fd_borrowed_account_get_owner( &view_acc ), owner, sizeof(fd_pubkey_t) ) ) {
     564           0 :         int err = fd_borrowed_account_set_owner( &view_acc, owner );
     565           0 :         if( FD_UNLIKELY( err ) ) {
     566           0 :           return err;
     567           0 :         }
     568           0 :       }
     569        3270 :     }
     570        3534 :   }
     571             : 
     572        2253 :   return FD_EXECUTOR_INSTR_SUCCESS;
     573        2373 : }
     574             : 
     575             : static int
     576             : fd_bpf_loader_input_serialize_for_abiv0( fd_exec_instr_ctx_t *     ctx,
     577             :                                          ulong *                   pre_lens,
     578             :                                          fd_vm_input_region_t *    input_mem_regions,
     579             :                                          uint *                    input_mem_regions_cnt,
     580             :                                          fd_vm_acc_region_meta_t * acc_region_metas,
     581             :                                          int                       virtual_address_space_adjustments,
     582             :                                          int                       direct_mapping,
     583             :                                          ulong *                   instr_data_offset,
     584         108 :                                          ulong *                   serialized_bytes_written ) {
     585         108 :   fd_pubkey_t const * txn_accs = ctx->txn_out->accounts.keys;
     586             : 
     587             :   /* Transaction sanitisation limits the number of instruction accounts to
     588             :      FD_TXN_ACCT_ADDR_MAX. */
     589         108 :   uchar  acc_idx_seen[ FD_TXN_ACCT_ADDR_MAX ] = {0};
     590         108 :   ushort dup_acc_idx[ FD_TXN_ACCT_ADDR_MAX ]  = {0};
     591             : 
     592             :   /* 16-byte aligned buffer:
     593             :      https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L61 */
     594         108 :   uchar * serialized_params            = ctx->runtime->bpf_loader_serialization.serialization_mem[ ctx->runtime->instr.stack_sz-1UL ];
     595         108 :   uchar * serialized_params_start      = serialized_params;
     596         108 :   uchar * curr_serialized_params_start = serialized_params;
     597         108 :   ulong   curr_region_vaddr            = 0UL;
     598             : 
     599         108 :   FD_STORE( ulong, serialized_params, ctx->instr->acct_cnt );
     600         108 :   serialized_params += sizeof(ulong);
     601             : 
     602         342 :   for( ushort i=0; i<ctx->instr->acct_cnt; i++ ) {
     603         234 :     uchar               acc_idx = (uchar)ctx->instr->accounts[i].index_in_transaction;
     604         234 :     fd_pubkey_t const * acc     = &txn_accs[acc_idx];
     605             : 
     606         234 :     if( FD_UNLIKELY( acc_idx_seen[acc_idx] && dup_acc_idx[acc_idx] != i ) ) {
     607             :       // Duplicate
     608          54 :       FD_STORE( uchar, serialized_params, (uchar)dup_acc_idx[acc_idx] );
     609          54 :       serialized_params += sizeof(uchar);
     610             : 
     611             :       /* Clone the account metadata from the original account
     612             :          https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L382 */
     613          54 :       acc_region_metas[i] = acc_region_metas[dup_acc_idx[acc_idx]];
     614         180 :     } else {
     615         180 :       acc_idx_seen[acc_idx] = 1;
     616         180 :       dup_acc_idx[acc_idx]  = i;
     617             : 
     618         180 :       FD_STORE( uchar, serialized_params, FD_NON_DUP_MARKER );
     619         180 :       serialized_params += sizeof(uchar);
     620             : 
     621             :       /* Borrow the account
     622             :          https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L253 */
     623         180 :       fd_guarded_borrowed_account_t view_acc = {0};
     624         180 :       int err = fd_exec_instr_ctx_try_borrow_instr_account( ctx, i, &view_acc );
     625         180 :       if( FD_UNLIKELY( err ) ) {
     626           0 :         return err;
     627           0 :       }
     628             : 
     629         180 :       fd_account_meta_t const * metadata = fd_borrowed_account_get_acc_meta( &view_acc );
     630             : 
     631         180 :       pre_lens[i] = metadata->dlen;
     632             : 
     633         180 :       uchar is_signer = (uchar)fd_instr_acc_is_signer_idx( ctx->instr, (uchar)i, NULL );
     634         180 :       FD_STORE( uchar, serialized_params, is_signer );
     635         180 :       serialized_params += sizeof(uchar);
     636             : 
     637         180 :       uchar is_writable = (uchar)fd_instr_acc_is_writable_idx( ctx->instr, (uchar)i );
     638         180 :       FD_STORE( uchar, serialized_params, is_writable );
     639         180 :       serialized_params += sizeof(uchar);
     640             : 
     641         180 :       fd_pubkey_t key = *acc;
     642         180 :       acc_region_metas[i].vm_key_addr = FD_VM_MEM_MAP_INPUT_REGION_START + curr_region_vaddr +
     643         180 :         (ulong)(serialized_params - curr_serialized_params_start);
     644         180 :       FD_STORE( fd_pubkey_t, serialized_params, key );
     645         180 :       serialized_params += sizeof(fd_pubkey_t);
     646             : 
     647         180 :       ulong lamports = metadata->lamports;
     648         180 :       acc_region_metas[i].vm_lamports_addr = FD_VM_MEM_MAP_INPUT_REGION_START + curr_region_vaddr +
     649         180 :         (ulong)(serialized_params - curr_serialized_params_start);
     650         180 :       FD_STORE( ulong, serialized_params, lamports );
     651         180 :       serialized_params += sizeof(ulong);
     652             : 
     653         180 :       ulong acc_data_len = metadata->dlen;
     654         180 :       FD_STORE( ulong, serialized_params, acc_data_len );
     655         180 :       serialized_params += sizeof(ulong);
     656             : 
     657             :       /* vm_data_addr: data is written immediately after the data_len field */
     658         180 :       acc_region_metas[i].vm_data_addr = FD_VM_MEM_MAP_INPUT_REGION_START + curr_region_vaddr +
     659         180 :         (ulong)(serialized_params - curr_serialized_params_start);
     660             : 
     661         180 :       write_account( &view_acc, (uchar)i,
     662         180 :         &serialized_params, &curr_serialized_params_start,
     663         180 :         input_mem_regions, input_mem_regions_cnt, acc_region_metas, 1,
     664         180 :         virtual_address_space_adjustments, direct_mapping );
     665             : 
     666             :       /* write_account may have pushed a new region(s) */
     667         180 :       curr_region_vaddr = *input_mem_regions_cnt == 0U ? 0UL :
     668         180 :         input_mem_regions[*input_mem_regions_cnt-1U].vaddr_offset +
     669         120 :         input_mem_regions[*input_mem_regions_cnt-1U].address_space_reserved;
     670             : 
     671         180 :       fd_pubkey_t owner = *(fd_pubkey_t *)&metadata->owner;
     672         180 :       acc_region_metas[i].vm_owner_addr = FD_VM_MEM_MAP_INPUT_REGION_START + curr_region_vaddr +
     673         180 :         (ulong)(serialized_params - curr_serialized_params_start);
     674         180 :       FD_STORE( fd_pubkey_t, serialized_params, owner );
     675         180 :       serialized_params += sizeof(fd_pubkey_t);
     676             : 
     677         180 :       uchar is_executable = (uchar)metadata->executable;
     678         180 :       FD_STORE( uchar, serialized_params, is_executable );
     679         180 :       serialized_params += sizeof(uchar);
     680             : 
     681         180 :       FD_STORE( ulong, serialized_params, ULONG_MAX );
     682         180 :       serialized_params += sizeof(ulong);
     683         180 :     }
     684         234 :   }
     685             : 
     686         108 :   ulong instr_data_len = ctx->instr->data_sz;
     687         108 :   FD_STORE( ulong, serialized_params, instr_data_len );
     688         108 :   serialized_params += sizeof(ulong);
     689             : 
     690             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L399 */
     691         108 :   *instr_data_offset = FD_VM_MEM_MAP_INPUT_REGION_START + curr_region_vaddr +
     692         108 :     (ulong)(serialized_params - curr_serialized_params_start);
     693             : 
     694         108 :   fd_memcpy( serialized_params, ctx->instr->data, instr_data_len );
     695         108 :   serialized_params += instr_data_len;
     696             : 
     697         108 :   FD_STORE( fd_pubkey_t, serialized_params, txn_accs[ctx->instr->program_id] );
     698         108 :   serialized_params += sizeof(fd_pubkey_t);
     699             : 
     700         108 :   *serialized_bytes_written = (ulong)(serialized_params - serialized_params_start);
     701             : 
     702         108 :   ulong region_sz = (ulong)(serialized_params - curr_serialized_params_start);
     703         108 :   new_input_mem_region( input_mem_regions, input_mem_regions_cnt, curr_serialized_params_start,
     704         108 :     region_sz, region_sz, 1U, ULONG_MAX );
     705             : 
     706         108 :   return FD_EXECUTOR_INSTR_SUCCESS;
     707         108 : }
     708             : 
     709             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L411 */
     710             : static int
     711             : fd_bpf_loader_input_deserialize_for_abiv0( fd_exec_instr_ctx_t * ctx,
     712             :                                            ulong const *         pre_lens,
     713             :                                            uchar *               input,
     714             :                                            ulong                 input_sz,
     715             :                                            int                   virtual_address_space_adjustments,
     716           0 :                                            int                   direct_mapping ) {
     717           0 :   uchar *       input_cursor      = input;
     718           0 :   uchar         acc_idx_seen[256] = {0};
     719             : 
     720           0 :   input_cursor += sizeof(ulong);
     721             : 
     722           0 :   for( ushort i=0; i<ctx->instr->acct_cnt; i++ ) {
     723           0 :     uchar acc_idx = (uchar)ctx->instr->accounts[i].index_in_transaction;
     724             : 
     725           0 :     input_cursor++; /* is_dup */
     726           0 :     if( FD_UNLIKELY( acc_idx_seen[acc_idx] ) ) {
     727             :       /* no-op */
     728           0 :     } else {
     729           0 :       acc_idx_seen[acc_idx] = 1;
     730           0 :       input_cursor += sizeof(uchar) +      /* is_signer */
     731           0 :                       sizeof(uchar) +      /* is_writable */
     732           0 :                       sizeof(fd_pubkey_t); /* key */
     733             : 
     734             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L427-L428 */
     735           0 :       fd_guarded_borrowed_account_t view_acc = {0};
     736           0 :       FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, i, &view_acc );
     737             : 
     738           0 :       ulong lamports = FD_LOAD( ulong, input_cursor );
     739           0 :       if( fd_borrowed_account_get_acc_meta( &view_acc ) && fd_borrowed_account_get_lamports( &view_acc )!=lamports ) {
     740           0 :         int err = fd_borrowed_account_set_lamports( &view_acc, lamports );
     741           0 :         if( FD_UNLIKELY( err ) ) {
     742           0 :           return err;
     743           0 :         }
     744           0 :       }
     745             : 
     746           0 :       input_cursor += sizeof(ulong); /* lamports */
     747           0 :       input_cursor += sizeof(ulong); /* data length */
     748             : 
     749           0 :       ulong   pre_len   = pre_lens[i];
     750           0 :       uchar * post_data = input_cursor;
     751             : 
     752             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L443-L453 */
     753           0 :       int can_data_be_changed_err = 0;
     754           0 :       if( !virtual_address_space_adjustments ) {
     755           0 :         int can_data_be_resized_err = 0;
     756           0 :         if( fd_borrowed_account_can_data_be_resized( &view_acc, pre_len, &can_data_be_resized_err ) &&
     757           0 :             fd_borrowed_account_can_data_be_changed( &view_acc, &can_data_be_changed_err ) ) {
     758           0 :           int set_data_err = fd_borrowed_account_set_data_from_slice( &view_acc, post_data, pre_len );
     759           0 :           if( FD_UNLIKELY( set_data_err ) ) {
     760           0 :             return set_data_err;
     761           0 :           }
     762           0 :         } else if( fd_borrowed_account_get_data_len( &view_acc ) != pre_len ||
     763           0 :                      memcmp( post_data, fd_borrowed_account_get_data( &view_acc ), pre_len ) ) {
     764           0 :             return can_data_be_resized_err ? can_data_be_resized_err : can_data_be_changed_err;
     765           0 :           }
     766           0 :       } else if( !direct_mapping && fd_borrowed_account_can_data_be_changed( &view_acc, &can_data_be_changed_err ) ) {
     767             :         /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L453-L459 */
     768           0 :         int set_data_err = fd_borrowed_account_set_data_from_slice( &view_acc, post_data, pre_len );
     769           0 :         if( FD_UNLIKELY( set_data_err ) ) {
     770           0 :           return set_data_err;
     771           0 :         }
     772           0 :       } else if( fd_borrowed_account_get_data_len( &view_acc ) != pre_len ) {
     773             :         /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L459-L461 */
     774           0 :         int set_data_length_err = fd_borrowed_account_set_data_length( &view_acc, pre_len );
     775           0 :         if( FD_UNLIKELY( set_data_length_err ) ) {
     776           0 :           return set_data_length_err;
     777           0 :         }
     778           0 :       }
     779             : 
     780             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L462-L464 */
     781           0 :       if( !( virtual_address_space_adjustments && direct_mapping ) ) {
     782           0 :         input_cursor += pre_len;
     783           0 :       }
     784           0 :       input_cursor += sizeof(fd_pubkey_t) + /* owner */
     785           0 :                       sizeof(uchar) +       /* executable */
     786           0 :                       sizeof(ulong);        /* rent_epoch*/
     787           0 :     }
     788           0 :   }
     789             : 
     790           0 :   if( FD_UNLIKELY( input_cursor>input+input_sz ) ) {
     791           0 :     return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
     792           0 :   }
     793             : 
     794           0 :   return 0;
     795           0 : }
     796             : 
     797             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L222 */
     798             : int
     799             : fd_bpf_loader_input_serialize_parameters( fd_exec_instr_ctx_t *     instr_ctx,
     800             :                                           ulong *                   pre_lens,
     801             :                                           fd_vm_input_region_t *    input_mem_regions,
     802             :                                           uint *                    input_mem_regions_cnt,
     803             :                                           fd_vm_acc_region_meta_t * acc_region_metas,
     804             :                                           int                       virtual_address_space_adjustments,
     805             :                                           int                       direct_mapping,
     806             :                                           int                       direct_account_pointers_in_program_input,
     807             :                                           uchar                     is_deprecated,
     808             :                                           ulong *                   instr_data_offset,
     809        2964 :                                           ulong *                   serialized_bytes_written ) {
     810             : 
     811             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L236-L239 */
     812        2964 :   ulong num_ix_accounts = instr_ctx->instr->acct_cnt;
     813        2964 :   if( FD_UNLIKELY( num_ix_accounts>FD_BPF_INSTR_ACCT_MAX ) ) {
     814           0 :     return FD_EXECUTOR_INSTR_ERR_MAX_ACCS_EXCEEDED;
     815           0 :   }
     816             : 
     817             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L265-L285 */
     818        2964 :   if( FD_UNLIKELY( is_deprecated ) ) {
     819         108 :     return fd_bpf_loader_input_serialize_for_abiv0( instr_ctx, pre_lens,
     820         108 :                                                     input_mem_regions, input_mem_regions_cnt,
     821         108 :                                                     acc_region_metas, virtual_address_space_adjustments,
     822         108 :                                                     direct_mapping, instr_data_offset, serialized_bytes_written );
     823        2856 :   } else {
     824        2856 :     return fd_bpf_loader_input_serialize_for_abiv1( instr_ctx, pre_lens,
     825        2856 :                                                     input_mem_regions, input_mem_regions_cnt,
     826        2856 :                                                     acc_region_metas, virtual_address_space_adjustments,
     827        2856 :                                                     direct_mapping, direct_account_pointers_in_program_input,
     828        2856 :                                                     instr_data_offset, serialized_bytes_written );
     829        2856 :   }
     830        2964 : }
     831             : 
     832             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.3/program-runtime/src/serialization.rs#L288-L317 */
     833             : int
     834             : fd_bpf_loader_input_deserialize_parameters( fd_exec_instr_ctx_t * ctx,
     835             :                                             ulong const *         pre_lens,
     836             :                                             uchar *               input,
     837             :                                             ulong                 input_sz,
     838             :                                             int                   virtual_address_space_adjustments,
     839             :                                             int                   direct_mapping,
     840        2373 :                                             uchar                 is_deprecated ) {
     841        2373 :   if( FD_UNLIKELY( is_deprecated ) ) {
     842           0 :     return fd_bpf_loader_input_deserialize_for_abiv0(
     843           0 :       ctx, pre_lens, input, input_sz, virtual_address_space_adjustments, direct_mapping );
     844        2373 :   } else {
     845        2373 :     return fd_bpf_loader_input_deserialize_for_abiv1(
     846        2373 :       ctx, pre_lens, input, input_sz, virtual_address_space_adjustments, direct_mapping );
     847        2373 :   }
     848        2373 : }

Generated by: LCOV version 1.14