LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_core_bpf_migration.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 281 0.0 %
Date: 2025-09-19 04:41:14 Functions: 0 5 0.0 %

          Line data    Source code
       1             : #include "context/fd_exec_slot_ctx.h"
       2             : #include "sysvar/fd_sysvar_rent.h"
       3             : #include "program/fd_bpf_loader_program.h"
       4             : #include "program/fd_builtin_programs.h"
       5             : #include "fd_pubkey_utils.h"
       6             : 
       7             : /* Mimics bank.new_target_program_account(). Assumes out_rec is a
       8             :    modifiable record.
       9             : 
      10             :    From the calling context, out_rec points to a native program record
      11             :    (e.g. Config, ALUT native programs). There should be enough space in
      12             :    out_rec->data to hold at least 36 bytes (the size of a BPF
      13             :    upgradeable program account) when calling this function. The native
      14             :    program account's owner is set to the BPF loader upgradeable program
      15             :    ID, and lamports are increased / deducted to contain the rent exempt
      16             :    minimum balance.
      17             : 
      18             :    https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L79-L95 */
      19             : static int
      20             : fd_new_target_program_account( fd_exec_slot_ctx_t * slot_ctx,
      21             :                                fd_pubkey_t const *  target_program_data_address,
      22           0 :                                fd_txn_account_t *   out_rec ) {
      23             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L86-L88 */
      24           0 :   fd_bpf_upgradeable_loader_state_t state = {
      25           0 :     .discriminant = fd_bpf_upgradeable_loader_state_enum_program,
      26           0 :     .inner = {
      27           0 :       .program = {
      28           0 :         .programdata_address = *target_program_data_address,
      29           0 :       }
      30           0 :     }
      31           0 :   };
      32             : 
      33             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L89-L90 */
      34           0 :   fd_rent_t const * rent = fd_bank_rent_query( slot_ctx->bank );
      35           0 :   if( FD_UNLIKELY( rent==NULL ) ) {
      36           0 :     return -1;
      37           0 :   }
      38             : 
      39           0 :   fd_txn_account_set_lamports( out_rec, fd_rent_exempt_minimum_balance( rent, SIZE_OF_PROGRAM ) );
      40           0 :   fd_bincode_encode_ctx_t ctx = {
      41           0 :     .data    = fd_txn_account_get_data_mut( out_rec ),
      42           0 :     .dataend = fd_txn_account_get_data_mut( out_rec ) + SIZE_OF_PROGRAM,
      43           0 :   };
      44             : 
      45             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L91-L9 */
      46           0 :   int err = fd_bpf_upgradeable_loader_state_encode( &state, &ctx );
      47           0 :   if( FD_UNLIKELY( err ) ) {
      48           0 :     return err;
      49           0 :   }
      50           0 :   fd_txn_account_set_owner( out_rec, &fd_solana_bpf_loader_upgradeable_program_id );
      51             : 
      52             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L93-L94 */
      53           0 :   fd_txn_account_set_executable( out_rec, 1 );
      54           0 :   return FD_RUNTIME_EXECUTE_SUCCESS;
      55           0 : }
      56             : 
      57             : /* Mimics bank.new_target_program_data_account(). Assumes
      58             :    new_target_program_data_account is a modifiable record.
      59             :    config_upgrade_authority_address may be NULL.
      60             : 
      61             :    This function uses an existing buffer account buffer_acc_rec to set
      62             :    the program data account data for a core program BPF migration. Sets
      63             :    the lamports and data fields of new_target_program_data_account
      64             :    based on the ELF data length, and sets the owner to the BPF loader
      65             :    upgradeable program ID.
      66             : 
      67             :    https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L97-L153 */
      68             : static int
      69             : fd_new_target_program_data_account( fd_exec_slot_ctx_t * slot_ctx,
      70             :                                     fd_pubkey_t *        config_upgrade_authority_address,
      71             :                                     fd_txn_account_t *   buffer_acc_rec,
      72             :                                     fd_txn_account_t *   new_target_program_data_account,
      73           0 :                                     fd_spad_t *          runtime_spad ) {
      74             : 
      75           0 :   FD_SPAD_FRAME_BEGIN( runtime_spad ) {
      76             : 
      77             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L113-L116 */
      78           0 :   int err;
      79           0 :   fd_bpf_upgradeable_loader_state_t * state = fd_bincode_decode_spad(
      80           0 :       bpf_upgradeable_loader_state, runtime_spad,
      81           0 :       fd_txn_account_get_data( buffer_acc_rec ),
      82           0 :       fd_txn_account_get_data_len( buffer_acc_rec ),
      83           0 :       &err );
      84           0 :   if( FD_UNLIKELY( err ) ) return err;
      85             : 
      86           0 :   if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_buffer( state ) ) ) {
      87           0 :     return -1;
      88           0 :   }
      89             : 
      90             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L118-L125 */
      91           0 :   if( config_upgrade_authority_address!=NULL ) {
      92           0 :     if( FD_UNLIKELY( !state->inner.buffer.has_authority_address ||
      93           0 :                      !fd_pubkey_eq( config_upgrade_authority_address, &state->inner.buffer.authority_address ) ) ) {
      94           0 :       return -1;
      95           0 :     }
      96           0 :   }
      97             : 
      98             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L127-L132 */
      99           0 :   fd_rent_t const * rent = fd_bank_rent_query( slot_ctx->bank );
     100           0 :   if( FD_UNLIKELY( rent==NULL ) ) {
     101           0 :     return -1;
     102           0 :   }
     103             : 
     104           0 :   const uchar * elf = fd_txn_account_get_data( buffer_acc_rec ) + BUFFER_METADATA_SIZE;
     105           0 :   ulong space = PROGRAMDATA_METADATA_SIZE - BUFFER_METADATA_SIZE + fd_txn_account_get_data_len( buffer_acc_rec );
     106           0 :   ulong lamports = fd_rent_exempt_minimum_balance( rent, space );
     107             : 
     108             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L134-L137 */
     109           0 :   fd_bpf_upgradeable_loader_state_t programdata_metadata = {
     110           0 :     .discriminant = fd_bpf_upgradeable_loader_state_enum_program_data,
     111           0 :     .inner = {
     112           0 :       .program_data = {
     113           0 :         .slot = fd_bank_slot_get( slot_ctx->bank ),
     114           0 :         .has_upgrade_authority_address = !!config_upgrade_authority_address,
     115           0 :         .upgrade_authority_address     = config_upgrade_authority_address ? *config_upgrade_authority_address : (fd_pubkey_t){{0}}
     116           0 :       }
     117           0 :     }
     118           0 :   };
     119             : 
     120             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L139-L144 */
     121           0 :   fd_txn_account_set_lamports( new_target_program_data_account, lamports );
     122           0 :   fd_bincode_encode_ctx_t encode_ctx = {
     123           0 :     .data    = fd_txn_account_get_data_mut( new_target_program_data_account ),
     124           0 :     .dataend = fd_txn_account_get_data_mut( new_target_program_data_account ) + PROGRAMDATA_METADATA_SIZE,
     125           0 :   };
     126           0 :   err = fd_bpf_upgradeable_loader_state_encode( &programdata_metadata, &encode_ctx );
     127           0 :   if( FD_UNLIKELY( err ) ) {
     128           0 :     return err;
     129           0 :   }
     130           0 :   fd_txn_account_set_owner( new_target_program_data_account, &fd_solana_bpf_loader_upgradeable_program_id );
     131             : 
     132             :   /* Copy the ELF data over
     133             :      https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L145 */
     134           0 :   fd_memcpy( fd_txn_account_get_data_mut( new_target_program_data_account ) + PROGRAMDATA_METADATA_SIZE, elf, fd_txn_account_get_data_len( buffer_acc_rec ) - BUFFER_METADATA_SIZE );
     135             : 
     136           0 :   return FD_RUNTIME_EXECUTE_SUCCESS;
     137             : 
     138           0 :   } FD_SPAD_FRAME_END;
     139           0 : }
     140             : 
     141             : /* Initializes a source buffer account from funk. Returns 1 if the
     142             :    buffer account does not exist or is not owned by the upgradeable
     143             :    loader. Returns 0 on success.
     144             : 
     145             :    https://github.com/anza-xyz/agave/blob/v2.3.0/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L22-L49 */
     146             : static int
     147             : fd_source_buffer_account_new( fd_exec_slot_ctx_t * slot_ctx,
     148             :                               fd_txn_account_t *   buffer_account,
     149             :                               fd_pubkey_t const *  buffer_address,
     150           0 :                               fd_funk_rec_prepare_t * prepare ) {
     151             :   /* The buffer account should exist.
     152             :      https://github.com/anza-xyz/agave/blob/v2.3.0/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L27-L29 */
     153           0 :   if( FD_UNLIKELY( fd_txn_account_init_from_funk_mutable( buffer_account, buffer_address, slot_ctx->funk, slot_ctx->funk_txn, 0, 0UL, prepare )!=FD_ACC_MGR_SUCCESS ) ) {
     154           0 :     FD_LOG_DEBUG(( "Buffer account %s does not exist, skipping migration...", FD_BASE58_ENC_32_ALLOCA( buffer_address ) ));
     155           0 :     return 1;
     156           0 :   }
     157             : 
     158             :   /* The buffer account should be owned by the upgradeable loader.
     159             :      https://github.com/anza-xyz/agave/blob/v2.3.0/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L31-L34 */
     160           0 :   if( FD_UNLIKELY( memcmp( fd_txn_account_get_owner( buffer_account ), fd_solana_bpf_loader_upgradeable_program_id.uc, sizeof(fd_pubkey_t) ) ) ) {
     161           0 :     FD_LOG_DEBUG(( "Buffer account %s is not owned by the upgradeable loader, skipping migration...", FD_BASE58_ENC_32_ALLOCA( buffer_address ) ));
     162           0 :     return 1;
     163           0 :   }
     164             : 
     165             :   /* The buffer account should have the correct state. We already check
     166             :      the buffer account state in fd_new_target_program_data_account(),
     167             :      so we can skip the checks here.
     168             :      https://github.com/anza-xyz/agave/blob/v2.3.0/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L37-L47 */
     169             : 
     170           0 :   return 0;
     171           0 : }
     172             : 
     173             : /* Similar to fd_source_buffer_account_new() but also checks the build
     174             :    hash of the buffer account for verification. verified_build_hash must
     175             :    be valid and non-NULL. Returns 1 if fd_source_buffer_account_new()
     176             :    fails, the buffer dlen is too small, or if the build hash mismatches.
     177             :    Returns 0 on success.
     178             : 
     179             :    https://github.com/anza-xyz/agave/blob/v2.3.0/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L51-L75 */
     180             : static int
     181             : fd_source_buffer_account_new_with_hash( fd_exec_slot_ctx_t *    slot_ctx,
     182             :                                         fd_txn_account_t *      buffer_account,
     183             :                                         fd_pubkey_t const *     buffer_address,
     184             :                                         fd_hash_t const *       verified_build_hash,
     185           0 :                                         fd_funk_rec_prepare_t * prepare ) {
     186             :   /* https://github.com/anza-xyz/agave/blob/v2.3.0/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L58 */
     187           0 :   int err = fd_source_buffer_account_new( slot_ctx, buffer_account, buffer_address, prepare );
     188           0 :   if( FD_UNLIKELY( err ) ) {
     189           0 :     return err;
     190           0 :   }
     191             : 
     192             :   /* https://github.com/anza-xyz/agave/blob/v2.3.0/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L59 */
     193           0 :   uchar const * data = fd_txn_account_get_data( buffer_account );
     194           0 :   ulong         data_len = fd_txn_account_get_data_len( buffer_account );
     195             : 
     196             :   /* https://github.com/anza-xyz/agave/blob/v2.3.0/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61 */
     197           0 :   ulong offset = BUFFER_METADATA_SIZE;
     198           0 :   if( FD_UNLIKELY( data_len<offset ) ) {
     199           0 :     return 1;
     200           0 :   }
     201             : 
     202             :   /* Search for the first nonzero byte in the buffer account data starting
     203             :      from the right.
     204             :      https://github.com/anza-xyz/agave/blob/v2.3.0/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L62 */
     205           0 :   ulong end_offset = offset;
     206           0 :   for( ulong i=data_len-1UL; i>=offset; i-- ) {
     207           0 :     if( data[i]!=0 ) {
     208           0 :       end_offset = i+1UL;
     209           0 :       break;
     210           0 :     }
     211           0 :   }
     212             : 
     213             :   /* Compute and verify the hash.
     214             :      https://github.com/anza-xyz/agave/blob/v2.3.0/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L64-L71 */
     215           0 :   fd_hash_t hash[1];
     216           0 :   fd_sha256_hash( data+offset, end_offset-offset, hash );
     217           0 :   if( FD_UNLIKELY( memcmp( verified_build_hash, hash, sizeof(fd_hash_t) ) ) ) {
     218           0 :     FD_LOG_WARNING(( "Mismatching build hash for Buffer account %s (expected=%s, actual=%s). Skipping migration...", FD_BASE58_ENC_32_ALLOCA( buffer_address ), FD_BASE58_ENC_32_ALLOCA( verified_build_hash ), FD_BASE58_ENC_32_ALLOCA( hash ) ));
     219           0 :     return 1;
     220           0 :   }
     221             : 
     222           0 :   return 0;
     223           0 : }
     224             : 
     225             : /* Mimics migrate_builtin_to_core_bpf().
     226             :    https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L235-L318 */
     227             : void
     228             : fd_migrate_builtin_to_core_bpf( fd_exec_slot_ctx_t *                   slot_ctx,
     229             :                                 fd_core_bpf_migration_config_t const * config,
     230           0 :                                 fd_spad_t *                            runtime_spad ) {
     231           0 :   int err;
     232             : 
     233             :   /* Initialize local variables from the config */
     234           0 :   fd_pubkey_t const * source_buffer_address     = config->source_buffer_address;
     235           0 :   fd_pubkey_t *       upgrade_authority_address = config->upgrade_authority_address;
     236           0 :   uchar               stateless                 = !!( config->migration_target==FD_CORE_BPF_MIGRATION_TARGET_STATELESS );
     237           0 :   fd_pubkey_t const * builtin_program_id        = config->builtin_program_id;
     238           0 :   fd_hash_t const *   verified_build_hash       = config->verified_build_hash;
     239             : 
     240             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L242-L243
     241             : 
     242             :      The below logic is used to obtain a TargetBuiltin account. There
     243             :      are three fields of TargetBuiltin returned:
     244             :       - target.program_address: builtin_program_id
     245             :       - target.program_account:
     246             :           - if stateless: an AccountSharedData::default() (i.e. system
     247             :             program id, 0 lamports, 0 data, non-executable, system
     248             :             program owner)
     249             :           - if NOT stateless: the existing account (for us its called
     250             :             target_program_account)
     251             :       - target.program_data_address: target_program_data_address for
     252             :         us, derived below. */
     253             : 
     254             :   /* These checks will fail if the core program has already been migrated to BPF, since the account will exist + the program owner
     255             :      will no longer be the native loader.
     256             :      https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L23-L50 */
     257           0 :   FD_TXN_ACCOUNT_DECL( target_program_account );
     258           0 :   uchar program_exists = ( fd_txn_account_init_from_funk_readonly( target_program_account, builtin_program_id, slot_ctx->funk, slot_ctx->funk_txn )==FD_ACC_MGR_SUCCESS );
     259           0 :   if( !stateless ) {
     260             :     /* The program account should exist.
     261             :        https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L30-L33 */
     262           0 :     if( FD_UNLIKELY( !program_exists ) ) {
     263           0 :       FD_LOG_DEBUG(( "Builtin program %s does not exist, skipping migration...", FD_BASE58_ENC_32_ALLOCA( builtin_program_id ) ));
     264           0 :       return;
     265           0 :     }
     266             : 
     267             :     /* The program account should be owned by the native loader.
     268             :        https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L35-L38 */
     269           0 :     if( FD_UNLIKELY( memcmp( fd_txn_account_get_owner( target_program_account ), fd_solana_native_loader_id.uc, sizeof(fd_pubkey_t) ) ) ) {
     270           0 :       FD_LOG_DEBUG(( "Builtin program %s is not owned by the native loader, skipping migration...", FD_BASE58_ENC_32_ALLOCA( builtin_program_id ) ));
     271           0 :       return;
     272           0 :     }
     273           0 :   } else {
     274             :     /* The program account should _not_ exist.
     275             :        https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L42-L46 */
     276           0 :     if( FD_UNLIKELY( program_exists ) ) {
     277           0 :       FD_LOG_DEBUG(( "Stateless program %s already exists, skipping migration...", FD_BASE58_ENC_32_ALLOCA( builtin_program_id ) ));
     278           0 :       return;
     279           0 :     }
     280           0 :   }
     281             : 
     282             :   /* The program data account should not exist.
     283             :      https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L52-L62 */
     284           0 :   uint custom_err = UINT_MAX;
     285           0 :   fd_pubkey_t target_program_data_address[ 1UL ];
     286           0 :   uchar const * seeds[ 1UL ];
     287           0 :   seeds[ 0UL ]    = (uchar const *)builtin_program_id;
     288           0 :   ulong seed_sz   = sizeof(fd_pubkey_t);
     289           0 :   uchar bump_seed = 0;
     290           0 :   err = fd_pubkey_find_program_address( &fd_solana_bpf_loader_upgradeable_program_id, 1UL, seeds, &seed_sz, target_program_data_address, &bump_seed, &custom_err );
     291           0 :   if( FD_UNLIKELY( err ) ) {
     292             :     /* TODO: We should handle these errors more gracefully instead of just killing the client. */
     293           0 :     FD_LOG_ERR(( "Unable to find a viable program address bump seed" )); // Solana panics, error code is undefined
     294           0 :     return;
     295           0 :   }
     296           0 :   FD_TXN_ACCOUNT_DECL( program_data_account );
     297           0 :   if( FD_UNLIKELY( fd_txn_account_init_from_funk_readonly( program_data_account, target_program_data_address, slot_ctx->funk, slot_ctx->funk_txn )==FD_ACC_MGR_SUCCESS ) ) {
     298           0 :     FD_LOG_WARNING(( "Program data account %s already exists, skipping migration...", FD_BASE58_ENC_32_ALLOCA( target_program_data_address ) ));
     299           0 :     return;
     300           0 :   }
     301             : 
     302             :   /* https://github.com/anza-xyz/agave/blob/v2.3.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L221-L229
     303             : 
     304             :      Obtains a SourceBuffer account. There are two fields returned:
     305             :       - source.buffer_address: source_buffer_address
     306             :       - source.buffer_account: the existing buffer account
     307             :      Depending on if the verified build hash is provided,  */
     308           0 :   FD_TXN_ACCOUNT_DECL( source_buffer_account );
     309           0 :   fd_funk_rec_prepare_t source_buffer_prepare = {0};
     310           0 :   if( verified_build_hash!=NULL ) {
     311           0 :     if( FD_UNLIKELY( fd_source_buffer_account_new_with_hash( slot_ctx, source_buffer_account, source_buffer_address, verified_build_hash, &source_buffer_prepare ) ) ) {
     312           0 :       return;
     313           0 :     }
     314           0 :   } else {
     315           0 :     if( FD_UNLIKELY( fd_source_buffer_account_new( slot_ctx, source_buffer_account, source_buffer_address, &source_buffer_prepare ) ) ) {
     316           0 :       return;
     317           0 :     }
     318           0 :   }
     319             : 
     320           0 :   fd_lthash_value_t prev_source_buffer_hash[1];
     321           0 :   fd_hashes_account_lthash(
     322           0 :     source_buffer_address,
     323           0 :     fd_txn_account_get_meta( source_buffer_account ),
     324           0 :     fd_txn_account_get_data( source_buffer_account ),
     325           0 :     prev_source_buffer_hash );
     326             : 
     327             :   /* This check is done a bit prematurely because we calculate the
     328             :      previous account state's lamports. We use 0 for starting lamports
     329             :      for stateless accounts because they don't yet exist.
     330             : 
     331             :      https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L277-L280 */
     332           0 :   ulong lamports_to_burn = ( stateless ? 0UL : fd_txn_account_get_lamports( target_program_account ) ) + fd_txn_account_get_lamports( source_buffer_account );
     333             : 
     334             :   /* Start a funk write txn */
     335           0 :   fd_funk_txn_t * parent_txn = slot_ctx->funk_txn;
     336           0 :   fd_funk_txn_xid_t migration_xid = fd_funk_generate_xid();
     337           0 :   fd_funk_txn_start_write( slot_ctx->funk );
     338           0 :   slot_ctx->funk_txn = fd_funk_txn_prepare( slot_ctx->funk, slot_ctx->funk_txn, &migration_xid, 0UL );
     339           0 :   fd_funk_txn_end_write( slot_ctx->funk );
     340             : 
     341             :   /* Attempt serialization of program account. If the program is
     342             :      stateless, we want to create the account. Otherwise, we want a
     343             :      writable handle to modify the existing account.
     344             :      https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L246-L249 */
     345           0 :   FD_TXN_ACCOUNT_DECL( new_target_program_account );
     346           0 :   fd_funk_rec_prepare_t new_target_program_prepare = {0};
     347           0 :   err = fd_txn_account_init_from_funk_mutable(
     348           0 :       new_target_program_account,
     349           0 :       builtin_program_id,
     350           0 :       slot_ctx->funk,
     351           0 :       slot_ctx->funk_txn,
     352           0 :       stateless,
     353           0 :       SIZE_OF_PROGRAM,
     354           0 :       &new_target_program_prepare );
     355           0 :   if( FD_UNLIKELY( err ) ) {
     356           0 :     FD_LOG_WARNING(( "Builtin program ID %s does not exist", FD_BASE58_ENC_32_ALLOCA( builtin_program_id ) ));
     357           0 :     goto fail;
     358           0 :   }
     359           0 :   fd_lthash_value_t prev_new_target_program_account_hash[1];
     360           0 :   fd_hashes_account_lthash(
     361           0 :     builtin_program_id,
     362           0 :     fd_txn_account_get_meta( new_target_program_account ),
     363           0 :     fd_txn_account_get_data( new_target_program_account ),
     364           0 :     prev_new_target_program_account_hash );
     365           0 :   fd_txn_account_set_data_len( new_target_program_account, SIZE_OF_PROGRAM );
     366           0 :   fd_txn_account_set_slot( new_target_program_account, fd_bank_slot_get( slot_ctx->bank ) );
     367             : 
     368             :   /* Create a new target program account. This modifies the existing record. */
     369           0 :   err = fd_new_target_program_account( slot_ctx, target_program_data_address, new_target_program_account );
     370           0 :   if( FD_UNLIKELY( err ) ) {
     371           0 :     FD_LOG_WARNING(( "Failed to write new program state to %s", FD_BASE58_ENC_32_ALLOCA( builtin_program_id ) ));
     372           0 :     goto fail;
     373           0 :   }
     374             : 
     375           0 :   fd_hashes_update_lthash(
     376           0 :     new_target_program_account,
     377           0 :     prev_new_target_program_account_hash,
     378           0 :     slot_ctx->bank,
     379           0 :     slot_ctx->capture_ctx );
     380           0 :   fd_txn_account_mutable_fini( new_target_program_account, slot_ctx->funk, slot_ctx->funk_txn, &new_target_program_prepare );
     381             : 
     382             :   /* Create a new target program data account. */
     383           0 :   ulong new_target_program_data_account_sz = PROGRAMDATA_METADATA_SIZE - BUFFER_METADATA_SIZE + fd_txn_account_get_data_len( source_buffer_account );
     384           0 :   FD_TXN_ACCOUNT_DECL( new_target_program_data_account );
     385           0 :   fd_funk_rec_prepare_t new_target_program_data_prepare = {0};
     386           0 :   err = fd_txn_account_init_from_funk_mutable(
     387           0 :       new_target_program_data_account,
     388           0 :       target_program_data_address,
     389           0 :       slot_ctx->funk,
     390           0 :       slot_ctx->funk_txn,
     391           0 :       1,
     392           0 :       new_target_program_data_account_sz,
     393           0 :       &new_target_program_data_prepare );
     394           0 :   if( FD_UNLIKELY( err ) ) {
     395           0 :     FD_LOG_WARNING(( "Failed to create new program data account to %s", FD_BASE58_ENC_32_ALLOCA( target_program_data_address ) ));
     396           0 :     goto fail;
     397           0 :   }
     398           0 :   fd_lthash_value_t prev_new_target_program_data_account_hash[1];
     399           0 :   fd_hashes_account_lthash(
     400           0 :     target_program_data_address,
     401           0 :     fd_txn_account_get_meta( new_target_program_data_account ),
     402           0 :     fd_txn_account_get_data( new_target_program_data_account ),
     403           0 :     prev_new_target_program_data_account_hash );
     404           0 :   fd_txn_account_set_data_len( new_target_program_data_account, new_target_program_data_account_sz );
     405           0 :   fd_txn_account_set_slot( new_target_program_data_account, fd_bank_slot_get( slot_ctx->bank ) );
     406             : 
     407           0 :   err = fd_new_target_program_data_account( slot_ctx,
     408           0 :                                             upgrade_authority_address,
     409           0 :                                             source_buffer_account,
     410           0 :                                             new_target_program_data_account,
     411           0 :                                             runtime_spad );
     412           0 :   if( FD_UNLIKELY( err ) ) {
     413           0 :     FD_LOG_WARNING(( "Failed to write new program data state to %s", FD_BASE58_ENC_32_ALLOCA( target_program_data_address ) ));
     414           0 :     goto fail;
     415           0 :   }
     416             : 
     417           0 :   fd_hashes_update_lthash(
     418           0 :     new_target_program_data_account,
     419           0 :     prev_new_target_program_data_account_hash,
     420           0 :     slot_ctx->bank,
     421           0 :     slot_ctx->capture_ctx );
     422           0 :   fd_txn_account_mutable_fini( new_target_program_data_account, slot_ctx->funk, slot_ctx->funk_txn, &new_target_program_data_prepare );
     423             : 
     424             :   /* Deploy the new target Core BPF program.
     425             :      https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L268-L271 */
     426           0 :   err = fd_directly_invoke_loader_v3_deploy( slot_ctx,
     427           0 :                                              builtin_program_id,
     428           0 :                                              fd_txn_account_get_data( new_target_program_data_account ) + PROGRAMDATA_METADATA_SIZE,
     429           0 :                                              fd_txn_account_get_data_len( new_target_program_data_account ) - PROGRAMDATA_METADATA_SIZE,
     430           0 :                                              runtime_spad );
     431           0 :   if( FD_UNLIKELY( err ) ) {
     432           0 :     FD_LOG_WARNING(( "Failed to deploy program %s", FD_BASE58_ENC_32_ALLOCA( builtin_program_id ) ));
     433           0 :     goto fail;
     434           0 :   }
     435             : 
     436             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L281-L284 */
     437           0 :   ulong lamports_to_fund = fd_txn_account_get_lamports( new_target_program_account ) + fd_txn_account_get_lamports( new_target_program_data_account );
     438             : 
     439             :   /* Update capitalization.
     440             :      https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L286-L297 */
     441           0 :   if( lamports_to_burn>lamports_to_fund ) {
     442           0 :     fd_bank_capitalization_set( slot_ctx->bank, fd_bank_capitalization_get( slot_ctx->bank ) - ( lamports_to_burn - lamports_to_fund ) );
     443           0 :   } else {
     444           0 :     fd_bank_capitalization_set( slot_ctx->bank, fd_bank_capitalization_get( slot_ctx->bank ) + ( lamports_to_fund - lamports_to_burn ) );
     445           0 :   }
     446             : 
     447             :   /* Reclaim the source buffer account
     448             :      https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L305 */
     449           0 :   fd_txn_account_set_lamports( source_buffer_account, 0 );
     450           0 :   fd_txn_account_set_data_len( source_buffer_account, 0 );
     451           0 :   fd_txn_account_clear_owner( source_buffer_account );
     452             : 
     453           0 :   fd_hashes_update_lthash(
     454           0 :     source_buffer_account,
     455           0 :     prev_source_buffer_hash,
     456           0 :     slot_ctx->bank,
     457           0 :     slot_ctx->capture_ctx );
     458           0 :   fd_txn_account_mutable_fini( source_buffer_account, slot_ctx->funk, slot_ctx->funk_txn, &source_buffer_prepare );
     459             : 
     460             :   /* Publish the in-preparation transaction into the parent. We should not have to create
     461             :      a BPF cache entry here because the program is technically "delayed visibility", so the program
     462             :      should not be invokable until the next slot. The cache entry will be created at the end of the
     463             :      block as a part of the finalize routine. */
     464           0 :   fd_funk_txn_start_write( slot_ctx->funk );
     465           0 :   fd_funk_txn_publish_into_parent( slot_ctx->funk, slot_ctx->funk_txn, 1 );
     466           0 :   fd_funk_txn_end_write( slot_ctx->funk );
     467           0 :   slot_ctx->funk_txn = parent_txn;
     468           0 :   return;
     469             : 
     470           0 : fail:
     471             :   /* Cancel the in-preparation transaction and discard any in-progress changes. */
     472           0 :   fd_funk_txn_start_write( slot_ctx->funk );
     473           0 :   fd_funk_txn_cancel( slot_ctx->funk, slot_ctx->funk_txn, 0UL );
     474           0 :   fd_funk_txn_end_write( slot_ctx->funk );
     475           0 :   slot_ctx->funk_txn = parent_txn;
     476           0 : }

Generated by: LCOV version 1.14