LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_core_bpf_migration.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 67 382 17.5 %
Date: 2026-03-19 18:19:27 Functions: 6 13 46.2 %

          Line data    Source code
       1             : #include "sysvar/fd_sysvar_rent.h"
       2             : #include "program/fd_bpf_loader_program.h"
       3             : #include "program/fd_builtin_programs.h"
       4             : #include "program/fd_program_util.h"
       5             : #include "fd_runtime_stack.h"
       6             : #include "fd_pubkey_utils.h"
       7             : #include "fd_system_ids.h"
       8             : #include "fd_hashes.h"
       9             : #include "../accdb/fd_accdb_sync.h"
      10             : #include "../../ballet/sha256/fd_sha256.h"
      11             : #include <assert.h>
      12             : 
      13             : static fd_pubkey_t
      14           2 : get_program_data_address( fd_pubkey_t const * program_addr ) {
      15           2 :   uchar const * seed    = program_addr->uc;
      16           2 :   ulong         seed_sz = 32UL;
      17           2 :   fd_pubkey_t   out;
      18           2 :   uint          custom_err;
      19           2 :   uchar         out_bump_seed;
      20           2 :   int err = fd_pubkey_find_program_address( &fd_solana_bpf_loader_upgradeable_program_id, 1UL, &seed, &seed_sz, &out, &out_bump_seed, &custom_err );
      21           2 :   if( FD_UNLIKELY( err ) ) {
      22             :     /* https://github.com/anza-xyz/solana-sdk/blob/address%40v2.1.0/address/src/syscalls.rs#L277-L279 */
      23           0 :     FD_LOG_ERR(( "Unable to find a viable program address bump seed" ));
      24           0 :   }
      25           2 :   return out;
      26           2 : }
      27             : 
      28             : fd_tmp_account_t *
      29             : tmp_account_new( fd_tmp_account_t * acc,
      30           0 :                  ulong              acc_sz ) {
      31           0 :   acc->data_sz = acc_sz;
      32           0 :   fd_memset( acc->data, 0, acc_sz );
      33           0 :   return acc;
      34           0 : }
      35             : 
      36             : fd_tmp_account_t *
      37             : tmp_account_read( fd_tmp_account_t *        acc,
      38             :                   fd_accdb_user_t *         accdb,
      39             :                   fd_funk_txn_xid_t const * xid,
      40           2 :                   fd_pubkey_t const *       addr ) {
      41           2 :   fd_accdb_ro_t ro[1];
      42           2 :   if( FD_LIKELY( !fd_accdb_open_ro( accdb, ro, xid, addr ) ) ) return NULL;
      43           0 :   tmp_account_new( acc, fd_accdb_ref_data_sz( ro ) );
      44           0 :   acc->meta = *ro->meta;
      45           0 :   acc->addr = *addr;
      46           0 :   fd_memcpy( acc->data, fd_accdb_ref_data_const( ro ), fd_accdb_ref_data_sz( ro ) );
      47           0 :   acc->data_sz = fd_accdb_ref_data_sz( ro );
      48           0 :   fd_accdb_close_ro( accdb, ro );
      49           0 :   return acc;
      50           2 : }
      51             : 
      52             : void
      53             : tmp_account_store( fd_tmp_account_t *        acc,
      54             :                    fd_accdb_user_t *         accdb,
      55             :                    fd_funk_txn_xid_t const * xid,
      56             :                    fd_bank_t *               bank,
      57           0 :                    fd_capture_ctx_t *        capture_ctx ) {
      58           0 :   if( FD_UNLIKELY( fd_pubkey_eq( &acc->addr, &fd_solana_system_program_id ) ) ) {
      59           0 :     FD_LOG_ERR(( "Attempted to write to the system program account" ));
      60           0 :   }
      61             : 
      62           0 :   fd_accdb_rw_t rw[1];
      63           0 :   fd_accdb_open_rw( accdb, rw, xid, &acc->addr, acc->data_sz, FD_ACCDB_FLAG_CREATE );
      64           0 :   fd_lthash_value_t prev_hash[1];
      65           0 :   fd_hashes_account_lthash( &acc->addr, rw->meta, fd_accdb_ref_data_const( rw->ro ), prev_hash );
      66             : 
      67           0 :   fd_accdb_ref_exec_bit_set( rw, acc->meta.executable );
      68           0 :   fd_accdb_ref_owner_set   ( rw, acc->meta.owner      );
      69           0 :   fd_accdb_ref_lamports_set( rw, acc->meta.lamports   );
      70           0 :   fd_accdb_ref_data_set    ( accdb, rw, acc->data, acc->data_sz );
      71             : 
      72           0 :   fd_hashes_update_lthash( &acc->addr, rw->meta, prev_hash, bank, capture_ctx );
      73           0 :   fd_accdb_close_rw( accdb, rw );
      74           0 : }
      75             : 
      76             : /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_core_bpf.rs#L12 */
      77             : 
      78             : struct target_core_bpf {
      79             :   fd_pubkey_t        program_address;
      80             :   fd_tmp_account_t * program_data_account;
      81             :   fd_pubkey_t        upgrade_authority_address;
      82             :   uint               has_upgrade_authority_address : 1;
      83             : };
      84             : 
      85             : typedef struct target_core_bpf target_core_bpf_t;
      86             : 
      87             : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L19 */
      88             : 
      89             : struct target_builtin {
      90             :   fd_tmp_account_t * program_account;
      91             :   fd_pubkey_t        program_data_address;
      92             :   ulong              program_data_account_lamports;
      93             : };
      94             : 
      95             : typedef struct target_builtin target_builtin_t;
      96             : 
      97             : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L25-L91 */
      98             : 
      99             : target_builtin_t *
     100             : target_builtin_new_checked( target_builtin_t *        target_builtin,
     101             :                             fd_pubkey_t const *       program_address,
     102             :                             int                       migration_target,
     103             :                             int                       relax_programdata_account_check_migration,
     104             :                             fd_accdb_user_t *         accdb,
     105             :                             fd_funk_txn_xid_t const * xid,
     106           2 :                             fd_runtime_stack_t *      runtime_stack ) {
     107             : 
     108             :   /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L31-L53 */
     109             : 
     110           2 :   fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
     111           2 :   switch( migration_target ) {
     112           0 :   case FD_CORE_BPF_MIGRATION_TARGET_BUILTIN:
     113           0 :     if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, xid, program_address ) ) ) {
     114             :       /* CoreBpfMigrationError::AccountNotFound(*program_address) */
     115           0 :       return NULL;
     116           0 :     }
     117           0 :     if( FD_UNLIKELY( 0!=memcmp( program_account->meta.owner, &fd_solana_native_loader_id, 32 ) ) ) {
     118             :       /* CoreBpfMigrationError::IncorrectOwner(*program_address) */
     119           0 :       return NULL;
     120           0 :     }
     121           0 :     break;
     122           2 :   case FD_CORE_BPF_MIGRATION_TARGET_STATELESS: {
     123             :     /* Program account should not exist */
     124           2 :     fd_accdb_ro_t ro[1];
     125           2 :     int progdata_exists = !!fd_accdb_open_ro( accdb, ro, xid, program_address );
     126           2 :     if( progdata_exists ) {
     127             :       /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
     128           0 :       fd_accdb_close_ro( accdb, ro );
     129           0 :       return NULL;
     130           0 :     }
     131           2 :     break;
     132           2 :   }
     133           2 :   default:
     134           0 :     FD_LOG_ERR(( "invalid migration_target %d", migration_target ));
     135           2 :   }
     136             : 
     137             :   /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L55 */
     138             : 
     139           2 :   fd_pubkey_t program_data_address = get_program_data_address( program_address );
     140             : 
     141             :   /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L57-L82 */
     142             : 
     143           2 :   ulong program_data_account_lamports = 0UL;
     144           2 :   do {
     145             :     /* Program data account should not exist */
     146           2 :     fd_accdb_ro_t ro[1];
     147           2 :     int progdata_exists = !!fd_accdb_open_ro( accdb, ro, xid, &program_data_address );
     148             : 
     149             :     /* SIMD-0444: relax_programdata_account_check_migration
     150             :        https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L57-L70 */
     151           2 :     if( relax_programdata_account_check_migration ) {
     152             :       /* The program data account should not exist, but a system
     153             :          account with funded lamports is acceptable. */
     154           0 :       if( FD_UNLIKELY( progdata_exists ) ) {
     155           0 :         if( FD_UNLIKELY( 0!=memcmp( fd_accdb_ref_owner( ro ), &fd_solana_system_program_id, sizeof(fd_pubkey_t) ) ) ) {
     156             :           /* CoreBpfMigrationError::ProgramHasDataAccount(
     157             :                *program_address) */
     158           0 :           fd_accdb_close_ro( accdb, ro );
     159           0 :           return NULL;
     160           0 :         } else {
     161           0 :           program_data_account_lamports = fd_accdb_ref_lamports( ro );
     162           0 :           fd_accdb_close_ro( accdb, ro );
     163           0 :         }
     164           0 :       }
     165           2 :     } else {
     166             :       /* If relax_programdata_account_check_migration is not enabled,
     167             :          we do not allow the program data account to exist at all. */
     168           2 :       if( FD_UNLIKELY( progdata_exists ) ) {
     169             :         /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
     170           0 :         fd_accdb_close_ro( accdb, ro );
     171           0 :         return NULL;
     172           0 :       }
     173           2 :     }
     174           2 :   } while(0);
     175             : 
     176             :   /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L63-L67 */
     177             : 
     178           2 :   *target_builtin = (target_builtin_t) {
     179           2 :     .program_account               = program_account,
     180           2 :     .program_data_address          = program_data_address,
     181           2 :     .program_data_account_lamports = program_data_account_lamports
     182           2 :   };
     183           2 :   return target_builtin;
     184           2 : }
     185             : 
     186             : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/target_core_bpf.rs#L26-L93 */
     187             : static target_core_bpf_t *
     188             : target_core_bpf_new_checked( target_core_bpf_t *       target_core_bpf,
     189             :                              fd_pubkey_t const *       program_address,
     190             :                              fd_accdb_user_t *         accdb,
     191             :                              fd_funk_txn_xid_t const * xid,
     192           0 :                              fd_runtime_stack_t *      runtime_stack ) {
     193           0 :   fd_pubkey_t program_data_address = get_program_data_address( program_address );
     194             : 
     195             :   /* The program account should exist */
     196           0 :   fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
     197           0 :   if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, xid, program_address ) ) ) {
     198           0 :     return NULL;
     199           0 :   }
     200             : 
     201             :   /* The program account should be owned by the upgradeable loader */
     202           0 :   if( FD_UNLIKELY( 0!=memcmp( program_account->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) ) ) ) {
     203           0 :     return NULL;
     204           0 :   }
     205             : 
     206             :   /* The program account should be executable */
     207           0 :   if( FD_UNLIKELY( !program_account->meta.executable ) ) {
     208           0 :     return NULL;
     209           0 :   }
     210             : 
     211             :   /* Decode and validate program account state */
     212           0 :   fd_bpf_upgradeable_loader_state_t program_state[1];
     213           0 :   if( FD_UNLIKELY( FD_EXECUTOR_INSTR_SUCCESS!=fd_bpf_loader_program_get_state( &program_account->meta, program_state ) ) ) {
     214           0 :     return NULL;
     215           0 :   }
     216           0 :   if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_program( program_state ) ) ) {
     217           0 :     return NULL;
     218           0 :   }
     219           0 :   if( FD_UNLIKELY( 0!=memcmp( &program_state->inner.program.programdata_address, &program_data_address, sizeof(fd_pubkey_t) ) ) ) {
     220           0 :     return NULL;
     221           0 :   }
     222             : 
     223             :   /* The program data account should exist */
     224           0 :   fd_tmp_account_t * program_data_account = &runtime_stack->bpf_migration.new_target_program;
     225           0 :   if( FD_UNLIKELY( !tmp_account_read( program_data_account, accdb, xid, &program_data_address ) ) ) {
     226           0 :     return NULL;
     227           0 :   }
     228             : 
     229             :   /* The program data account should be owned by the upgradeable loader */
     230           0 :   if( FD_UNLIKELY( 0!=memcmp( program_data_account->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) ) ) ) {
     231           0 :     return NULL;
     232           0 :   }
     233             : 
     234             :   /* Decode and validate program data account state */
     235           0 :   fd_bpf_upgradeable_loader_state_t programdata_state[1];
     236           0 :   if( FD_UNLIKELY( FD_EXECUTOR_INSTR_SUCCESS!=fd_bpf_loader_program_get_state( &program_data_account->meta, programdata_state ) ) ) {
     237           0 :     return NULL;
     238           0 :   }
     239           0 :   if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_program_data( programdata_state ) ) ) {
     240           0 :     return NULL;
     241           0 :   }
     242             : 
     243             :   /* Extract upgrade authority from program data state */
     244           0 :   fd_pubkey_t upgrade_authority_address;
     245           0 :   if( programdata_state->inner.program_data.has_upgrade_authority_address ) {
     246           0 :     upgrade_authority_address = programdata_state->inner.program_data.upgrade_authority_address;
     247           0 :   } else {
     248           0 :     fd_memset( &upgrade_authority_address, 0, sizeof(fd_pubkey_t) );
     249           0 :   }
     250             : 
     251           0 :   *target_core_bpf = (target_core_bpf_t) {
     252           0 :     .program_address                = *program_address,
     253           0 :     .program_data_account           = program_data_account,
     254           0 :     .upgrade_authority_address      = upgrade_authority_address,
     255           0 :     .has_upgrade_authority_address  = (uint)!!programdata_state->inner.program_data.has_upgrade_authority_address
     256           0 :   };
     257           0 :   return target_core_bpf;
     258           0 : }
     259             : 
     260             : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L51-L75 */
     261             : 
     262             : static fd_tmp_account_t *
     263             : source_buffer_new_checked( fd_tmp_account_t *        acc,
     264             :                            fd_accdb_user_t *         accdb,
     265             :                            fd_funk_txn_xid_t const * xid,
     266             :                            fd_pubkey_t const *       pubkey,
     267           2 :                            fd_hash_t const *         verified_build_hash ) {
     268             : 
     269           2 :   if( FD_UNLIKELY( !tmp_account_read( acc, accdb, xid, pubkey ) ) ) {
     270             :     /* CoreBpfMigrationError::AccountNotFound(*buffer_address) */
     271           2 :     return NULL;
     272           2 :   }
     273             : 
     274           0 :   if( FD_UNLIKELY( 0!=memcmp( acc->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, 32 ) ) ) {
     275             :     /* CoreBpfMigrationError::IncorrectOwner(*buffer_address) */
     276           0 :     return NULL;
     277           0 :   }
     278             : 
     279           0 :   if( acc->data_sz < BUFFER_METADATA_SIZE ) {
     280             :     /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
     281           0 :     return NULL;
     282           0 :   }
     283             : 
     284           0 :   fd_bpf_upgradeable_loader_state_t state[1];
     285           0 :   if( FD_UNLIKELY( !fd_bincode_decode_static(
     286           0 :       bpf_upgradeable_loader_state, state,
     287           0 :       acc->data, BUFFER_METADATA_SIZE ) ) ) {
     288           0 :     return NULL;
     289           0 :   }
     290             : 
     291           0 :   if( FD_UNLIKELY( state->discriminant!=fd_bpf_upgradeable_loader_state_enum_buffer ) ) {
     292             :     /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
     293           0 :     return NULL;
     294           0 :   }
     295             : 
     296             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L71 */
     297           0 :   if( verified_build_hash ) {
     298             :     /* Strip trailing zero-padding before hashing
     299             :        https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L63 */
     300           0 :     uchar const * data       = (uchar const *)acc->data;
     301           0 :     ulong         offset     = BUFFER_METADATA_SIZE;
     302           0 :     ulong         end_offset = acc->data_sz;
     303           0 :     while( end_offset>offset && data[end_offset-1]==0 ) end_offset--;
     304           0 :     uchar const * buffer_program_data    = data + offset;
     305           0 :     ulong         buffer_program_data_sz = end_offset - offset;
     306             : 
     307           0 :     fd_hash_t hash;
     308           0 :     fd_sha256_hash( buffer_program_data, buffer_program_data_sz, hash.uc );
     309           0 :     if( FD_UNLIKELY( 0!=memcmp( hash.uc, verified_build_hash->uc, FD_HASH_FOOTPRINT ) ) ) {
     310             :       /* CoreBpfMigrationError::BuildHashMismatch */
     311           0 :       return NULL;
     312           0 :     }
     313           0 :   }
     314             : 
     315           0 :   return acc;
     316           0 : }
     317             : 
     318             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L82-L95 */
     319             : 
     320             : static fd_tmp_account_t *
     321             : new_target_program_account( fd_tmp_account_t *        acc,
     322             :                             target_builtin_t const *  target,
     323           0 :                             fd_rent_t const *         rent ) {
     324             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L86-L88 */
     325           0 :   fd_bpf_upgradeable_loader_state_t state = {
     326           0 :     .discriminant = fd_bpf_upgradeable_loader_state_enum_program,
     327           0 :     .inner = {
     328           0 :       .program = {
     329           0 :         .programdata_address = target->program_data_address,
     330           0 :       }
     331           0 :     }
     332           0 :   };
     333             : 
     334           0 :   ulong state_sz = fd_bpf_upgradeable_loader_state_size( &state );
     335           0 :   tmp_account_new( acc, state_sz );
     336           0 :   acc->meta.lamports   = fd_rent_exempt_minimum_balance( rent, SIZE_OF_PROGRAM );
     337           0 :   acc->meta.executable = 1;
     338           0 :   memcpy( acc->meta.owner, fd_solana_bpf_loader_upgradeable_program_id.uc, sizeof(fd_pubkey_t) );
     339             : 
     340           0 :   fd_bincode_encode_ctx_t ctx = { .data=acc->data, .dataend=(uchar *)acc->data+state_sz };
     341           0 :   if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_encode( &state, &ctx )!=FD_BINCODE_SUCCESS ) ) {
     342           0 :     FD_LOG_ERR(( "fd_bpf_upgradeable_loader_state_encode failed" ));
     343           0 :   }
     344             : 
     345           0 :   return acc;
     346           0 : }
     347             : 
     348             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L108-L153 */
     349             : static fd_tmp_account_t *
     350             : new_target_program_data_account( fd_tmp_account_t *       acc,
     351             :                                  fd_tmp_account_t const * source,
     352             :                                  fd_pubkey_t const *      upgrade_authority_address,
     353             :                                  fd_rent_t const *        rent,
     354           0 :                                  ulong                    slot ) {
     355           0 :   ulong const buffer_metadata_sz = BUFFER_METADATA_SIZE;
     356             : 
     357           0 :   if( FD_UNLIKELY( source->data_sz < buffer_metadata_sz ) )
     358           0 :     return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
     359             : 
     360           0 :   fd_bpf_upgradeable_loader_state_t state;
     361           0 :   if( !fd_bincode_decode_static(
     362           0 :       bpf_upgradeable_loader_state,
     363           0 :       &state,
     364           0 :       source->data,
     365           0 :       buffer_metadata_sz ) )
     366           0 :     return NULL;
     367             : 
     368           0 :   if( FD_UNLIKELY( state.discriminant!=fd_bpf_upgradeable_loader_state_enum_buffer ) )
     369           0 :     return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
     370             : 
     371             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L118-L125 */
     372           0 :   if( upgrade_authority_address ) {
     373           0 :     if( FD_UNLIKELY( !state.inner.buffer.has_authority_address ||
     374           0 :                      !fd_pubkey_eq( upgrade_authority_address, &state.inner.buffer.authority_address ) ) ) {
     375           0 :       return NULL; /* CoreBpfMigrationError::UpgradeAuthorityMismatch */
     376           0 :     }
     377           0 :   }
     378             : 
     379           0 :   void const * elf      = (uchar const *)source->data    + buffer_metadata_sz;
     380           0 :   ulong        elf_sz   = /*           */source->data_sz - buffer_metadata_sz;
     381             : 
     382           0 :   ulong        space    = PROGRAMDATA_METADATA_SIZE + elf_sz;
     383           0 :   ulong        lamports = fd_rent_exempt_minimum_balance( rent, space );
     384           0 :   fd_pubkey_t  owner    = fd_solana_bpf_loader_upgradeable_program_id;
     385             : 
     386           0 :   fd_bpf_upgradeable_loader_state_t programdata_meta = {
     387           0 :     .discriminant = fd_bpf_upgradeable_loader_state_enum_program_data,
     388           0 :     .inner = {
     389           0 :       .program_data = {
     390           0 :         .slot = slot,
     391           0 :         .has_upgrade_authority_address = !!upgrade_authority_address,
     392           0 :         .upgrade_authority_address     = upgrade_authority_address ? *upgrade_authority_address : (fd_pubkey_t){{0}}
     393           0 :       }
     394           0 :     }
     395           0 :   };
     396             : 
     397           0 :   tmp_account_new( acc, space );
     398           0 :   acc->meta.lamports = lamports;
     399           0 :   memcpy( acc->meta.owner, owner.uc, sizeof(fd_pubkey_t) );
     400           0 :   fd_bincode_encode_ctx_t ctx = { .data=acc->data, .dataend=(uchar *)acc->data+PROGRAMDATA_METADATA_SIZE };
     401           0 :   if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_encode( &programdata_meta, &ctx )!=FD_BINCODE_SUCCESS ) ) {
     402           0 :     FD_LOG_ERR(( "fd_bpf_upgradeable_loader_state_encode failed" ));
     403           0 :   }
     404           0 :   fd_memcpy( (uchar *)acc->data+PROGRAMDATA_METADATA_SIZE, elf, elf_sz );
     405             : 
     406           0 :   return acc;
     407           0 : }
     408             : 
     409             : /* Mimics update_captalization()
     410             :    https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L471-L490 */
     411             : static inline int
     412             : fd_update_capitalization( fd_bank_t * bank,
     413             :                           ulong       lamports_to_burn,
     414           0 :                           ulong       lamports_to_fund ) {
     415           0 :   if( lamports_to_burn > lamports_to_fund ) {
     416           0 :     ulong diff;
     417           0 :     int err = fd_ulong_checked_sub( lamports_to_burn, lamports_to_fund, &diff );
     418           0 :     if( FD_UNLIKELY( err ) ) return err;
     419             : 
     420           0 :     ulong capitalization = fd_bank_capitalization_get( bank );
     421           0 :     ulong new_capitalization;
     422           0 :     err = fd_ulong_checked_sub( capitalization, diff, &new_capitalization );
     423           0 :     if( FD_UNLIKELY( err ) ) return err;
     424             : 
     425           0 :     fd_bank_capitalization_set( bank, new_capitalization );
     426           0 :   } else if( lamports_to_fund > lamports_to_burn ) {
     427           0 :     ulong diff;
     428           0 :     int err = fd_ulong_checked_sub( lamports_to_fund, lamports_to_burn, &diff );
     429           0 :     if( FD_UNLIKELY( err ) ) return err;
     430             : 
     431           0 :     ulong capitalization = fd_bank_capitalization_get( bank );
     432           0 :     ulong new_capitalization;
     433           0 :     err = fd_ulong_checked_add( capitalization, diff, &new_capitalization );
     434           0 :     if( FD_UNLIKELY( err ) ) return err;
     435             : 
     436           0 :     fd_bank_capitalization_set( bank, new_capitalization );
     437           0 :   }
     438             : 
     439           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     440           0 : }
     441             : 
     442             : void
     443             : migrate_builtin_to_core_bpf1( fd_core_bpf_migration_config_t const * config,
     444             :                               fd_accdb_user_t *                      accdb,
     445             :                               fd_funk_txn_xid_t const *              xid,
     446             :                               fd_bank_t *                            bank,
     447             :                               fd_runtime_stack_t *                   runtime_stack,
     448             :                               fd_pubkey_t const *                    builtin_program_id,
     449           2 :                               fd_capture_ctx_t *                     capture_ctx ) {
     450           2 :   target_builtin_t target[1];
     451           2 :   if( FD_UNLIKELY( !target_builtin_new_checked(
     452           2 :       target,
     453           2 :       builtin_program_id,
     454           2 :       config->migration_target,
     455           2 :       FD_FEATURE_ACTIVE_BANK( bank, relax_programdata_account_check_migration ),
     456           2 :       accdb,
     457           2 :       xid,
     458           2 :       runtime_stack ) ) )
     459           0 :     return;
     460             : 
     461           2 :   fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
     462           2 :   if( FD_UNLIKELY( !source_buffer_new_checked(
     463           2 :       source,
     464           2 :       accdb,
     465           2 :       xid,
     466           2 :       config->source_buffer_address,
     467           2 :       config->verified_build_hash ) ) )
     468           2 :     return;
     469             : 
     470           0 :   fd_rent_t const * rent = fd_bank_rent_query( bank );
     471           0 :   ulong const       slot = fd_bank_slot_get  ( bank );
     472             : 
     473           0 :   fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration.new_target_program;
     474           0 :   if( FD_UNLIKELY( !new_target_program_account(
     475           0 :       new_target_program,
     476           0 :       target,
     477           0 :       rent ) ) )
     478           0 :     return;
     479           0 :   new_target_program->addr = *builtin_program_id;
     480             : 
     481           0 :   fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
     482           0 :   if( FD_UNLIKELY( !new_target_program_data_account(
     483           0 :       new_target_program_data,
     484           0 :       source,
     485           0 :       config->upgrade_authority_address,
     486           0 :       rent,
     487           0 :       slot ) ) )
     488           0 :     return;
     489           0 :   new_target_program_data->addr = target->program_data_address;
     490             : 
     491           0 :   ulong old_data_sz;
     492           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
     493             : 
     494           0 :   ulong new_data_sz;
     495           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return;
     496             : 
     497           0 :   assert( new_target_program_data->data_sz>=PROGRAMDATA_METADATA_SIZE );
     498             :   /* FIXME call fd_directly_invoke_loader_v3_deploy */
     499             : 
     500             :   /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L267-L281 */
     501           0 :   ulong lamports_to_burn;
     502           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->meta.lamports, source->meta.lamports, &lamports_to_burn ) ) ) return;
     503           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) )       return;
     504             : 
     505           0 :   ulong lamports_to_fund;
     506           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->meta.lamports, new_target_program_data->meta.lamports, &lamports_to_fund ) ) ) return;
     507             : 
     508             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L286-L297 */
     509           0 :   if( FD_UNLIKELY( fd_update_capitalization( bank, lamports_to_burn, lamports_to_fund ) ) ) {
     510           0 :     FD_LOG_ERR(( "Capitalization overflow while migrating builtin program to core BPF" ));
     511           0 :   }
     512             : 
     513             :   /* Write back accounts */
     514           0 :   tmp_account_store( new_target_program,      accdb, xid, bank, capture_ctx );
     515           0 :   tmp_account_store( new_target_program_data, accdb, xid, bank, capture_ctx );
     516           0 :   fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
     517           0 :   tmp_account_new( empty, 0UL );
     518           0 :   empty->addr = source->addr;
     519           0 :   tmp_account_store( empty, accdb, xid, bank, capture_ctx );
     520             : 
     521             :   /* FIXME "remove the built-in program from the bank's list of builtins" */
     522             :   /* FIXME "update account data size delta" */
     523           0 : }
     524             : 
     525             : /* Mimics migrate_builtin_to_core_bpf().
     526             :    https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#215-303 */
     527             : void
     528             : fd_migrate_builtin_to_core_bpf( fd_bank_t *                            bank,
     529             :                                 fd_accdb_user_t *                      accdb,
     530             :                                 fd_funk_txn_xid_t const *              xid,
     531             :                                 fd_runtime_stack_t *                   runtime_stack,
     532             :                                 fd_core_bpf_migration_config_t const * config,
     533           2 :                                 fd_capture_ctx_t *                     capture_ctx ) {
     534           2 :   migrate_builtin_to_core_bpf1( config, accdb, xid, bank, runtime_stack, config->builtin_program_id, capture_ctx );
     535           2 : }
     536             : 
     537             : /* Mimics upgrade_core_bpf_program().
     538             :    https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L319-L377 */
     539             : void
     540             : fd_upgrade_core_bpf_program( fd_bank_t *                            bank,
     541             :                              fd_accdb_user_t *                      accdb,
     542             :                              fd_funk_txn_xid_t const *              xid,
     543             :                              fd_runtime_stack_t *                   runtime_stack,
     544             :                              fd_pubkey_t const *                    builtin_program_id,
     545             :                              fd_pubkey_t const *                    source_buffer_address,
     546           0 :                              fd_capture_ctx_t *                     capture_ctx ) {
     547             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L327 */
     548           0 :   target_core_bpf_t target[1];
     549           0 :   if( FD_UNLIKELY( !target_core_bpf_new_checked( target, builtin_program_id, accdb, xid, runtime_stack ) ) ) {
     550           0 :     return;
     551           0 :   }
     552             : 
     553             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L328 */
     554           0 :   fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
     555           0 :   if( FD_UNLIKELY( !source_buffer_new_checked( source, accdb, xid, source_buffer_address, NULL ) ) ) {
     556           0 :     return;
     557           0 :   }
     558             : 
     559             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L331-L332  */
     560           0 :   fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
     561           0 :   fd_pubkey_t program_data_address = get_program_data_address( builtin_program_id );
     562             : 
     563           0 :   ulong program_data_len = source->data_sz - BUFFER_METADATA_SIZE;
     564           0 :   ulong new_account_size = PROGRAMDATA_METADATA_SIZE + program_data_len;
     565             : 
     566           0 :   tmp_account_new( new_target_program_data, new_account_size );
     567           0 :   new_target_program_data->addr = program_data_address;
     568             : 
     569           0 :   fd_rent_t const * rent = fd_bank_rent_query( bank );
     570           0 :   new_target_program_data->meta.lamports   = fd_rent_exempt_minimum_balance( rent, new_account_size );
     571           0 :   new_target_program_data->meta.executable = 0;
     572           0 :   fd_memcpy( new_target_program_data->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) );
     573             : 
     574           0 :   fd_bpf_upgradeable_loader_state_t programdata_state[1] = {{
     575           0 :     .discriminant = fd_bpf_upgradeable_loader_state_enum_program_data,
     576           0 :     .inner = { .program_data = {
     577           0 :       .slot = fd_bank_slot_get( bank ),
     578           0 :       .upgrade_authority_address = target->upgrade_authority_address,
     579           0 :       .has_upgrade_authority_address = target->has_upgrade_authority_address
     580           0 :     }}
     581           0 :   }};
     582             : 
     583           0 :   fd_bincode_encode_ctx_t encode_ctx = {
     584           0 :     .data    = new_target_program_data->data,
     585           0 :     .dataend = new_target_program_data->data + PROGRAMDATA_METADATA_SIZE
     586           0 :   };
     587           0 :   if( FD_UNLIKELY( FD_BINCODE_SUCCESS!=fd_bpf_upgradeable_loader_state_encode( programdata_state, &encode_ctx ) ) ) {
     588           0 :     return;
     589           0 :   }
     590             : 
     591           0 :   fd_memcpy( new_target_program_data->data + PROGRAMDATA_METADATA_SIZE,
     592           0 :              source->data + BUFFER_METADATA_SIZE,
     593           0 :              program_data_len );
     594             : 
     595             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L338-L342 */
     596           0 :   ulong old_data_sz;
     597           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
     598           0 :   ulong new_data_sz = new_target_program_data->data_sz;
     599             : 
     600             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L359-L364 */
     601           0 :   ulong lamports_to_burn;
     602           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->meta.lamports, source->meta.lamports, &lamports_to_burn ) ) ) return;
     603           0 :   ulong lamports_to_fund = new_target_program_data->meta.lamports;
     604             : 
     605             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L364 */
     606           0 :   int err = fd_update_capitalization( bank, lamports_to_burn, lamports_to_fund );
     607           0 :   if( FD_UNLIKELY( err ) ) {
     608           0 :     FD_LOG_ERR(( "Capitalization overflow while migrating builtin program to core BPF" ));
     609           0 :   }
     610             : 
     611             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L366-L371 */
     612           0 :   fd_pubkey_t source_addr = source->addr;
     613           0 :   tmp_account_store( new_target_program_data, accdb, xid, bank, capture_ctx );
     614             : 
     615           0 :   fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
     616           0 :   tmp_account_new( empty, 0UL );
     617           0 :   empty->addr = source_addr;
     618           0 :   tmp_account_store( empty, accdb, xid, bank, capture_ctx );
     619             : 
     620             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L374 */
     621             :   /* FIXME "update account data size delta" */
     622           0 :   (void)old_data_sz;
     623           0 :   (void)new_data_sz;
     624             : 
     625           0 :   fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
     626           0 : }

Generated by: LCOV version 1.14