LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_core_bpf_migration.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 334 517 64.6 %
Date: 2026-08-28 06:53:58 Functions: 13 15 86.7 %

          Line data    Source code
       1             : #include "fd_accdb_svm.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 "program/fd_program_util.h"
       6             : #include "fd_runtime_stack.h"
       7             : #include "fd_pubkey_utils.h"
       8             : #include "fd_system_ids.h"
       9             : #include "../../ballet/sha256/fd_sha256.h"
      10             : #include "../../ballet/sbpf/fd_sbpf_loader.h"
      11             : #include "../progcache/fd_prog_load.h"
      12             : #include "../vm/fd_vm.h"
      13             : 
      14             : static fd_pubkey_t
      15           9 : get_program_data_address( fd_pubkey_t const * program_addr ) {
      16           9 :   uchar const * seed    = program_addr->uc;
      17           9 :   ulong         seed_sz = 32UL;
      18           9 :   fd_pubkey_t   out;
      19           9 :   uint          custom_err;
      20           9 :   uchar         out_bump_seed;
      21           9 :   int err = fd_pubkey_find_program_address( &fd_solana_bpf_loader_upgradeable_program_id, 1UL, &seed, &seed_sz, &out, &out_bump_seed, &custom_err );
      22           9 :   if( FD_UNLIKELY( err ) ) {
      23             :     /* https://github.com/anza-xyz/solana-sdk/blob/address%40v2.1.0/address/src/syscalls.rs#L277-L279 */
      24           0 :     FD_LOG_ERR(( "Unable to find a viable program address bump seed" ));
      25           0 :   }
      26           9 :   return out;
      27           9 : }
      28             : 
      29             : fd_tmp_account_t *
      30             : tmp_account_new( fd_tmp_account_t * acc,
      31          18 :                  ulong              acc_sz ) {
      32          18 :   acc->data_sz = acc_sz;
      33          18 :   fd_memset( acc->data,  0, acc_sz );
      34          18 :   acc->lamports = 0UL;
      35          18 :   acc->executable = 0;
      36          18 :   fd_memset( acc->owner.uc, 0, 32UL );
      37          18 :   fd_memset( acc->pubkey.uc, 0, 32UL );
      38          18 :   return acc;
      39          18 : }
      40             : 
      41             : fd_tmp_account_t *
      42             : tmp_account_read( fd_tmp_account_t *        acc,
      43             :                   fd_accdb_t *              accdb,
      44             :                   fd_accdb_fork_id_t        fork_id,
      45          15 :                   fd_pubkey_t const *       addr ) {
      46          15 :   fd_acc_t db_acc = fd_accdb_read_one( accdb, fork_id, addr->uc );
      47          15 :   if( FD_UNLIKELY( !db_acc.lamports ) ) {
      48           0 :     fd_accdb_unread_one( accdb, &db_acc );
      49           0 :     return NULL;
      50           0 :   }
      51             : 
      52          15 :   acc->lamports = db_acc.lamports;
      53          15 :   fd_memcpy( acc->owner.uc, db_acc.owner, 32UL );
      54          15 :   acc->executable = db_acc.executable;
      55          15 :   fd_memcpy( acc->data, db_acc.data, db_acc.data_len );
      56          15 :   acc->data_sz = db_acc.data_len;
      57          15 :   acc->pubkey = *addr;
      58             : 
      59          15 :   fd_accdb_unread_one( accdb, &db_acc );
      60          15 :   return acc;
      61          15 : }
      62             : 
      63             : /* pd_write must be 1 when acc is a programdata account being written
      64             :    with program_data.slot == the current slot. */
      65             : 
      66             : void
      67             : tmp_account_store( fd_bank_t *        bank,
      68             :                    fd_accdb_t *       accdb,
      69             :                    fd_tmp_account_t * acc,
      70             :                    fd_capture_ctx_t * capture_ctx,
      71          15 :                    int                pd_write ) {
      72          15 :   if( FD_UNLIKELY( fd_pubkey_eq( &acc->pubkey, &fd_solana_system_program_id ) ) ) FD_LOG_ERR(( "attempted to write to the system program account" ));
      73             : 
      74          15 :   fd_accdb_svm_update_t update[1];
      75          15 :   fd_acc_t db_acc = fd_accdb_svm_open_rw( bank, accdb, update, &acc->pubkey, 1 );
      76             : 
      77          15 :   db_acc.executable = acc->executable;
      78          15 :   fd_memcpy( db_acc.owner, acc->owner.uc, 32UL );
      79          15 :   db_acc.lamports = acc->lamports;
      80          15 :   fd_memcpy( db_acc.data, acc->data, acc->data_sz );
      81          15 :   db_acc.data_len = acc->data_sz;
      82          15 :   db_acc.pd_write = pd_write;
      83             : 
      84          15 :   fd_accdb_svm_close_rw( bank, accdb, capture_ctx, &db_acc, update );
      85          15 : }
      86             : 
      87             : /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_core_bpf.rs#L12 */
      88             : 
      89             : struct target_core_bpf {
      90             :   fd_pubkey_t        program_address;
      91             :   fd_tmp_account_t * program_data_account;
      92             :   fd_pubkey_t        upgrade_authority_address;
      93             :   uint               has_upgrade_authority_address : 1;
      94             : };
      95             : 
      96             : typedef struct target_core_bpf target_core_bpf_t;
      97             : 
      98             : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L19 */
      99             : 
     100             : struct target_builtin {
     101             :   fd_tmp_account_t * program_account;
     102             :   fd_pubkey_t        program_data_address;
     103             :   ulong              program_data_account_lamports;
     104             : };
     105             : 
     106             : typedef struct target_builtin target_builtin_t;
     107             : 
     108             : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L25-L91 */
     109             : 
     110             : target_builtin_t *
     111             : target_builtin_new_checked( target_builtin_t *        target_builtin,
     112             :                             fd_pubkey_t const *       program_address,
     113             :                             int                       migration_target,
     114             :                             int                       relax_programdata_account_check_migration,
     115             :                             fd_accdb_t *              accdb,
     116             :                             fd_accdb_fork_id_t        fork_id,
     117           3 :                             fd_runtime_stack_t *      runtime_stack ) {
     118             : 
     119             :   /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L31-L53 */
     120             : 
     121           3 :   fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
     122           3 :   switch( migration_target ) {
     123           3 :   case FD_CORE_BPF_MIGRATION_TARGET_BUILTIN:
     124           3 :     if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, fork_id, program_address ) ) ) {
     125             :       /* CoreBpfMigrationError::AccountNotFound(*program_address) */
     126           0 :       return NULL;
     127           0 :     }
     128           3 :     if( FD_UNLIKELY( 0!=memcmp( program_account->owner.uc, &fd_solana_native_loader_id, 32 ) ) ) {
     129             :       /* CoreBpfMigrationError::IncorrectOwner(*program_address) */
     130           0 :       return NULL;
     131           0 :     }
     132           3 :     break;
     133           3 :   case FD_CORE_BPF_MIGRATION_TARGET_STATELESS: {
     134             :     /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
     135           0 :     if( FD_UNLIKELY( fd_accdb_exists( accdb, fork_id, program_address->uc ) ) ) return NULL;
     136           0 :     break;
     137           0 :   }
     138           0 :   default:
     139           0 :     FD_LOG_ERR(( "invalid migration_target %d", migration_target ));
     140           3 :   }
     141             : 
     142             :   /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L55 */
     143             : 
     144           3 :   fd_pubkey_t program_data_address = get_program_data_address( program_address );
     145             : 
     146             :   /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L57-L82 */
     147             : 
     148           3 :   ulong program_data_account_lamports = 0UL;
     149           3 :   do {
     150             :     /* Program data account should not exist */
     151           3 :     fd_acc_t progdata = fd_accdb_read_one( accdb, fork_id, program_data_address.uc );
     152           3 :     int progdata_exists = !!progdata.lamports;
     153           3 :     if( FD_UNLIKELY( !progdata_exists ) ) fd_accdb_unread_one( accdb, &progdata );
     154             : 
     155             :     /* SIMD-0444: relax_programdata_account_check_migration
     156             :        https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L57-L70 */
     157           3 :     if( relax_programdata_account_check_migration ) {
     158             :       /* The program data account should not exist, but a system
     159             :          account with funded lamports is acceptable. */
     160           3 :       if( FD_UNLIKELY( progdata_exists ) ) {
     161           3 :         if( FD_UNLIKELY( !fd_pubkey_eq( (fd_pubkey_t*)progdata.owner, &fd_solana_system_program_id ) ) ) {
     162             :           /* CoreBpfMigrationError::ProgramHasDataAccount(*program_address) */
     163           0 :           fd_accdb_unread_one( accdb, &progdata );
     164           0 :           return NULL;
     165           3 :         } else {
     166           3 :           program_data_account_lamports = progdata.lamports;
     167           3 :           fd_accdb_unread_one( accdb, &progdata );
     168           3 :         }
     169           3 :       }
     170           3 :     } else {
     171             :       /* If relax_programdata_account_check_migration is not enabled,
     172             :          we do not allow the program data account to exist at all. */
     173           0 :       if( FD_UNLIKELY( progdata_exists ) ) {
     174             :         /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
     175           0 :         fd_accdb_unread_one( accdb, &progdata );
     176           0 :         return NULL;
     177           0 :       }
     178           0 :     }
     179           3 :   } while(0);
     180             : 
     181             :   /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L63-L67 */
     182             : 
     183           3 :   *target_builtin = (target_builtin_t) {
     184           3 :     .program_account               = program_account,
     185           3 :     .program_data_address          = program_data_address,
     186           3 :     .program_data_account_lamports = program_data_account_lamports
     187           3 :   };
     188           3 :   return target_builtin;
     189           3 : }
     190             : 
     191             : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/target_core_bpf.rs#L26-L93 */
     192             : static target_core_bpf_t *
     193             : target_core_bpf_new_checked( target_core_bpf_t *  target_core_bpf,
     194             :                              fd_pubkey_t const *  program_address,
     195             :                              fd_accdb_t *         accdb,
     196             :                              fd_accdb_fork_id_t   fork_id,
     197           3 :                              fd_runtime_stack_t * runtime_stack ) {
     198           3 :   fd_pubkey_t program_data_address = get_program_data_address( program_address );
     199             : 
     200             :   /* The program account should exist */
     201           3 :   fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
     202           3 :   if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, fork_id, program_address ) ) ) {
     203           0 :     return NULL;
     204           0 :   }
     205             : 
     206             :   /* The program account should be owned by the upgradeable loader */
     207           3 :   if( FD_UNLIKELY( 0!=memcmp( &program_account->owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) ) ) ) {
     208           0 :     return NULL;
     209           0 :   }
     210             : 
     211             :   /* The program account should be executable */
     212           3 :   if( FD_UNLIKELY( !program_account->executable ) ) {
     213           0 :     return NULL;
     214           0 :   }
     215             : 
     216             :   /* Decode and validate program account state */
     217           3 :   fd_bpf_state_t program_state[1];
     218           3 :   if( FD_UNLIKELY( FD_EXECUTOR_INSTR_SUCCESS!=fd_bpf_loader_program_get_state2( program_account->data, program_account->data_sz, program_state ) ) ) {
     219           0 :     return NULL;
     220           0 :   }
     221           3 :   if( FD_UNLIKELY( program_state->discriminant!=FD_BPF_STATE_PROGRAM ) ) {
     222           0 :     return NULL;
     223           0 :   }
     224           3 :   if( FD_UNLIKELY( 0!=memcmp( &program_state->inner.program.programdata_address, &program_data_address, sizeof(fd_pubkey_t) ) ) ) {
     225           0 :     return NULL;
     226           0 :   }
     227             : 
     228             :   /* The program data account should exist */
     229           3 :   fd_tmp_account_t * program_data_account = &runtime_stack->bpf_migration.new_target_program;
     230           3 :   if( FD_UNLIKELY( !tmp_account_read( program_data_account, accdb, fork_id, &program_data_address ) ) ) {
     231           0 :     return NULL;
     232           0 :   }
     233             : 
     234             :   /* The program data account should be owned by the upgradeable loader */
     235           3 :   if( FD_UNLIKELY( 0!=memcmp( &program_data_account->owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) ) ) ) {
     236           0 :     return NULL;
     237           0 :   }
     238             : 
     239             :   /* Decode and validate program data account state */
     240           3 :   fd_bpf_state_t programdata_state[1];
     241           3 :   if( FD_UNLIKELY( FD_EXECUTOR_INSTR_SUCCESS!=fd_bpf_loader_program_get_state2( program_data_account->data, program_data_account->data_sz, programdata_state ) ) ) {
     242           0 :     return NULL;
     243           0 :   }
     244           3 :   if( FD_UNLIKELY( programdata_state->discriminant!=FD_BPF_STATE_PROGRAM_DATA ) ) {
     245           0 :     return NULL;
     246           0 :   }
     247             : 
     248             :   /* Extract upgrade authority from program data state */
     249           3 :   fd_pubkey_t upgrade_authority_address;
     250           3 :   if( programdata_state->inner.program_data.has_upgrade_authority_address ) {
     251           3 :     upgrade_authority_address = programdata_state->inner.program_data.upgrade_authority_address;
     252           3 :   } else {
     253           0 :     fd_memset( &upgrade_authority_address, 0, sizeof(fd_pubkey_t) );
     254           0 :   }
     255             : 
     256           3 :   *target_core_bpf = (target_core_bpf_t) {
     257           3 :     .program_address                = *program_address,
     258           3 :     .program_data_account           = program_data_account,
     259           3 :     .upgrade_authority_address      = upgrade_authority_address,
     260           3 :     .has_upgrade_authority_address  = (uint)!!programdata_state->inner.program_data.has_upgrade_authority_address
     261           3 :   };
     262           3 :   return target_core_bpf;
     263           3 : }
     264             : 
     265             : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L25-L82
     266             : 
     267             :    Agave uses a separate TargetBpfV2 struct, but it has the
     268             :    same layout as target_builtin_t so we reuse that. */
     269             : static target_builtin_t *
     270             : target_bpf_v2_new_checked( target_builtin_t *        target_bpf_v2,
     271             :                            fd_pubkey_t const *       program_address,
     272             :                            int                       allow_prefunded,
     273             :                            fd_accdb_t *              accdb,
     274             :                            fd_accdb_fork_id_t        fork_id,
     275           0 :                            fd_runtime_stack_t *      runtime_stack ) {
     276             : 
     277             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L30-L33 */
     278           0 :   fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
     279           0 :   if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, fork_id, program_address ) ) ) {
     280             :     /* CoreBpfMigrationError::AccountNotFound(*program_address) */
     281           0 :     return NULL;
     282           0 :   }
     283             : 
     284             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L35-L38 */
     285           0 :   if( FD_UNLIKELY( 0!=memcmp( &program_account->owner, &fd_solana_bpf_loader_program_id, sizeof(fd_pubkey_t) ) ) ) {
     286             :     /* CoreBpfMigrationError::IncorrectOwner(*program_address) */
     287           0 :     return NULL;
     288           0 :   }
     289             : 
     290             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L40-L45 */
     291           0 :   if( FD_UNLIKELY( !program_account->executable ) ) {
     292             :     /* CoreBpfMigrationError::ProgramAccountNotExecutable(*program_address) */
     293           0 :     return NULL;
     294           0 :   }
     295             : 
     296             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L47 */
     297           0 :   fd_pubkey_t program_data_address = get_program_data_address( program_address );
     298             : 
     299             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L49-L74 */
     300           0 :   ulong program_data_account_lamports = 0UL;
     301           0 :   do {
     302           0 :     fd_acc_t acc = fd_accdb_read_one( accdb, fork_id, program_data_address.uc );
     303           0 :     int progdata_exists = !!acc.lamports;
     304           0 :     if( FD_UNLIKELY( !progdata_exists ) ) fd_accdb_unread_one( accdb, &acc );
     305             : 
     306             :     /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L49-L74 */
     307           0 :     if( FD_LIKELY( allow_prefunded ) ) {
     308             :       /* The program data account should not exist, but a system
     309             :          account with funded lamports is acceptable.
     310             : 
     311             :          https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L50-L61 */
     312           0 :       if( FD_UNLIKELY( progdata_exists ) ) {
     313           0 :         if( FD_UNLIKELY( !fd_pubkey_eq( (fd_pubkey_t*)acc.owner, &fd_solana_system_program_id ) ) ) {
     314             :           /* CoreBpfMigrationError::ProgramHasDataAccount(*program_address) */
     315           0 :           fd_accdb_unread_one( accdb, &acc );
     316           0 :           return NULL;
     317           0 :         } else {
     318           0 :           program_data_account_lamports = acc.lamports;
     319           0 :           fd_accdb_unread_one( accdb, &acc );
     320           0 :         }
     321           0 :       }
     322           0 :     } else {
     323             :       /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L62-L74 */
     324           0 :       if( FD_UNLIKELY( progdata_exists ) ) {
     325             :         /* CoreBpfMigrationError::ProgramHasDataAccount(*program_address) */
     326           0 :         fd_accdb_unread_one( accdb, &acc );
     327           0 :         return NULL;
     328           0 :       }
     329           0 :     }
     330           0 :   } while(0);
     331             : 
     332           0 :   *target_bpf_v2 = (target_builtin_t) {
     333           0 :     .program_account               = program_account,
     334           0 :     .program_data_address          = program_data_address,
     335           0 :     .program_data_account_lamports = program_data_account_lamports
     336           0 :   };
     337           0 :   return target_bpf_v2;
     338           0 : }
     339             : 
     340             : /* This function contains the deployment checks that are equivalent to
     341             :    Agave's directly_invoke_loader_v3_deploy.
     342             : 
     343             :    There is no direct equivalent in Agave to this function, because
     344             :    we are not updating the program cache here. However, we do the same
     345             :    checks that our program cache does upon deployment.
     346             : 
     347             :    This is safe because the bpf migration code runs at the epoch
     348             :    boundary, before any transaction execution. The program cache
     349             :    automatically invalidates all programs at the start of an epoch
     350             :    boundary, so we do not need to explicitly update the cache during the
     351             :    migration.
     352             : 
     353             :    https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L120-L218 */
     354             : static int
     355             : fd_directly_invoke_loader_v3_deploy_checks( fd_bank_t const *    bank,
     356             :                                             fd_runtime_stack_t * runtime_stack,
     357             :                                             uchar const *        elf,
     358           3 :                                             ulong                elf_sz ) {
     359           3 :   fd_features_t const * features = &bank->f.features;
     360           3 :   ulong                 slot     = bank->f.slot;
     361             : 
     362             :   /* ELF verification with deploy checks enabled */
     363           3 :   fd_prog_versions_t versions = fd_prog_versions( features, slot );
     364           3 :   fd_sbpf_loader_config_t loader_config = {
     365           3 :     .elf_deploy_checks = 1,
     366           3 :     .sbpf_min_version  = versions.min_sbpf_version,
     367           3 :     .sbpf_max_version  = versions.max_sbpf_version,
     368           3 :   };
     369           3 :   fd_sbpf_elf_info_t elf_info[1];
     370           3 :   if( FD_UNLIKELY( fd_sbpf_elf_peek( elf_info, elf, elf_sz, &loader_config )!=FD_SBPF_ELF_SUCCESS ) ) return 1;
     371             : 
     372             :   /* Setup program (includes calldests) */
     373           3 :   fd_sbpf_program_t * prog = fd_sbpf_program_new(
     374           3 :     runtime_stack->bpf_migration.progcache_validate.sbpf_footprint,
     375           3 :     elf_info,
     376           3 :     runtime_stack->bpf_migration.progcache_validate.rodata );
     377           3 :   if( FD_UNLIKELY( !prog ) ) return 1;
     378             : 
     379           3 :   fd_sbpf_syscalls_t _syscalls[ FD_SBPF_SYSCALLS_SLOT_CNT ];
     380           3 :   fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_join( fd_sbpf_syscalls_new( _syscalls ) );
     381           3 :   if( FD_UNLIKELY( !syscalls ) ) return 1;
     382           3 :   if( FD_UNLIKELY( fd_vm_syscall_register_slot( syscalls, slot, features, /* is_deploy */ 1 )!=FD_VM_SUCCESS ) ) return 1;
     383             : 
     384             :   /* fd_sbpf_program_load checks */
     385           3 :   if( FD_UNLIKELY( fd_sbpf_program_load(
     386           3 :     prog,
     387           3 :     elf,
     388           3 :     elf_sz,
     389           3 :     syscalls,
     390           3 :     &loader_config,
     391           3 :     runtime_stack->bpf_migration.progcache_validate.programdata,
     392           3 :     sizeof(runtime_stack->bpf_migration.progcache_validate.programdata) ) ) ) return 1;
     393             : 
     394             :   /* fd_vm_validate checks */
     395           3 :   fd_vm_t _vm[1];
     396           3 :   fd_vm_t * vm = fd_vm_join( fd_vm_new( _vm ) );
     397           3 :   if( FD_UNLIKELY( !vm ) ) return 1;
     398           3 :   vm = fd_vm_init( vm,
     399           3 :                    NULL,
     400           3 :                    0UL,
     401           3 :                    0UL,
     402           3 :                    prog->rodata,
     403           3 :                    prog->rodata_sz,
     404           3 :                    prog->text,
     405           3 :                    prog->info.text_cnt,
     406           3 :                    prog->info.text_off,
     407           3 :                    prog->info.text_sz,
     408           3 :                    prog->entry_pc,
     409           3 :                    prog->calldests,
     410           3 :                    elf_info->sbpf_version,
     411           3 :                    syscalls,
     412           3 :                    NULL,
     413           3 :                    NULL,
     414           3 :                    NULL,
     415           3 :                    0U,
     416           3 :                    NULL,
     417           3 :                    0,
     418           3 :                    FD_FEATURE_ACTIVE( slot, features, account_data_direct_mapping ),
     419           3 :                    FD_FEATURE_ACTIVE( slot, features, syscall_parameter_address_restrictions ),
     420           3 :                    FD_FEATURE_ACTIVE( slot, features, virtual_address_space_adjustments ),
     421           3 :                    0,
     422           3 :                    0UL );
     423           3 :   if( FD_UNLIKELY( !vm ) ) return 1;
     424           3 :   if( FD_UNLIKELY( fd_vm_validate( vm )!=FD_VM_SUCCESS ) ) return 1;
     425             : 
     426           3 :   return FD_EXECUTOR_INSTR_SUCCESS;
     427           3 : }
     428             : 
     429             : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L51-L75 */
     430             : 
     431             : static fd_tmp_account_t *
     432             : source_buffer_new_checked( fd_tmp_account_t *  acc,
     433             :                            fd_accdb_t *        accdb,
     434             :                            fd_accdb_fork_id_t  fork_id,
     435             :                            fd_pubkey_t const * pubkey,
     436           6 :                            fd_hash_t const *   verified_build_hash ) {
     437             : 
     438           6 :   if( FD_UNLIKELY( !tmp_account_read( acc, accdb, fork_id, pubkey ) ) ) {
     439             :     /* CoreBpfMigrationError::AccountNotFound(*buffer_address) */
     440           0 :     return NULL;
     441           0 :   }
     442             : 
     443           6 :   if( FD_UNLIKELY( 0!=memcmp( acc->owner.uc, &fd_solana_bpf_loader_upgradeable_program_id, 32 ) ) ) {
     444             :     /* CoreBpfMigrationError::IncorrectOwner(*buffer_address) */
     445           0 :     return NULL;
     446           0 :   }
     447             : 
     448           6 :   if( acc->data_sz < BUFFER_METADATA_SIZE ) {
     449             :     /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
     450           0 :     return NULL;
     451           0 :   }
     452             : 
     453           6 :   fd_bpf_state_t state[1];
     454           6 :   if( FD_UNLIKELY( fd_bpf_state_decode( state, acc->data, BUFFER_METADATA_SIZE ) ) ) {
     455           0 :     return NULL;
     456           0 :   }
     457             : 
     458           6 :   if( FD_UNLIKELY( state->discriminant!=FD_BPF_STATE_BUFFER ) ) {
     459             :     /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
     460           0 :     return NULL;
     461           0 :   }
     462             : 
     463             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L71 */
     464           6 :   if( verified_build_hash ) {
     465             :     /* Strip trailing zero-padding before hashing
     466             :        https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L63 */
     467           0 :     uchar const * data       = (uchar const *)acc->data;
     468           0 :     ulong         offset     = BUFFER_METADATA_SIZE;
     469           0 :     ulong         end_offset = acc->data_sz;
     470           0 :     while( end_offset>offset && data[end_offset-1]==0 ) end_offset--;
     471           0 :     uchar const * buffer_program_data    = data + offset;
     472           0 :     ulong         buffer_program_data_sz = end_offset - offset;
     473             : 
     474           0 :     fd_hash_t hash;
     475           0 :     fd_sha256_hash( buffer_program_data, buffer_program_data_sz, hash.uc );
     476           0 :     if( FD_UNLIKELY( 0!=memcmp( hash.uc, verified_build_hash->uc, FD_HASH_FOOTPRINT ) ) ) {
     477             :       /* CoreBpfMigrationError::BuildHashMismatch */
     478           0 :       return NULL;
     479           0 :     }
     480           0 :   }
     481             : 
     482           6 :   return acc;
     483           6 : }
     484             : 
     485             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L82-L95 */
     486             : 
     487             : static fd_tmp_account_t *
     488             : new_target_program_account( fd_tmp_account_t *        acc,
     489             :                             target_builtin_t const *  target,
     490           3 :                             fd_rent_t const *         rent ) {
     491             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L86-L88 */
     492           3 :   fd_bpf_state_t state = {
     493           3 :     .discriminant = FD_BPF_STATE_PROGRAM,
     494           3 :     .inner = {
     495           3 :       .program = {
     496           3 :         .programdata_address = target->program_data_address,
     497           3 :       }
     498           3 :     }
     499           3 :   };
     500             : 
     501           3 :   ulong state_sz = fd_bpf_state_size( &state );
     502           3 :   tmp_account_new( acc, state_sz );
     503           3 :   acc->lamports   = fd_rent_exempt_minimum_balance( rent, SIZE_OF_PROGRAM );
     504           3 :   acc->executable = 1;
     505           3 :   memcpy( acc->owner.uc, fd_solana_bpf_loader_upgradeable_program_id.uc, sizeof(fd_pubkey_t) );
     506             : 
     507           3 :   ulong out_sz = 0UL;
     508           3 :   if( FD_UNLIKELY( fd_bpf_state_encode( &state, acc->data, state_sz, &out_sz ) ) ) {
     509           0 :     FD_LOG_ERR(( "fd_bpf_state_encode failed" ));
     510           0 :   }
     511             : 
     512           3 :   return acc;
     513           3 : }
     514             : 
     515             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L108-L153 */
     516             : static fd_tmp_account_t *
     517             : new_target_program_data_account( fd_tmp_account_t *       acc,
     518             :                                  fd_tmp_account_t const * source,
     519             :                                  fd_pubkey_t const *      upgrade_authority_address,
     520             :                                  fd_rent_t const *        rent,
     521           3 :                                  ulong                    slot ) {
     522           3 :   ulong const buffer_metadata_sz = BUFFER_METADATA_SIZE;
     523             : 
     524           3 :   if( FD_UNLIKELY( source->data_sz < buffer_metadata_sz ) )
     525           0 :     return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
     526             : 
     527           3 :   fd_bpf_state_t state;
     528           3 :   if( FD_UNLIKELY( fd_bpf_state_decode( &state, source->data, buffer_metadata_sz ) ) ) {
     529           0 :     return NULL;
     530           0 :   }
     531             : 
     532           3 :   if( FD_UNLIKELY( state.discriminant!=FD_BPF_STATE_BUFFER ) )
     533           0 :     return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
     534             : 
     535             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L118-L125 */
     536           3 :   if( upgrade_authority_address ) {
     537           0 :     if( FD_UNLIKELY( !state.inner.buffer.has_authority_address ||
     538           0 :                      !fd_pubkey_eq( upgrade_authority_address, &state.inner.buffer.authority_address ) ) ) {
     539           0 :       return NULL; /* CoreBpfMigrationError::UpgradeAuthorityMismatch */
     540           0 :     }
     541           0 :   }
     542             : 
     543           3 :   void const * elf      = (uchar const *)source->data    + buffer_metadata_sz;
     544           3 :   ulong        elf_sz   = /*           */source->data_sz - buffer_metadata_sz;
     545             : 
     546           3 :   ulong        space    = PROGRAMDATA_METADATA_SIZE + elf_sz;
     547           3 :   ulong        lamports = fd_rent_exempt_minimum_balance( rent, space );
     548           3 :   fd_pubkey_t  owner    = fd_solana_bpf_loader_upgradeable_program_id;
     549             : 
     550           3 :   fd_bpf_state_t programdata_meta = {
     551           3 :     .discriminant = FD_BPF_STATE_PROGRAM_DATA,
     552           3 :     .inner = {
     553           3 :       .program_data = {
     554           3 :         .slot = slot,
     555           3 :         .has_upgrade_authority_address = !!upgrade_authority_address,
     556           3 :         .upgrade_authority_address     = upgrade_authority_address ? *upgrade_authority_address : (fd_pubkey_t){{0}}
     557           3 :       }
     558           3 :     }
     559           3 :   };
     560             : 
     561           3 :   tmp_account_new( acc, space );
     562           3 :   acc->lamports = lamports;
     563           3 :   memcpy( acc->owner.uc, owner.uc, sizeof(fd_pubkey_t) );
     564           3 :   ulong out_sz = 0UL;
     565           3 :   if( FD_UNLIKELY( fd_bpf_state_encode( &programdata_meta, acc->data, PROGRAMDATA_METADATA_SIZE, &out_sz ) ) ) {
     566           0 :     FD_LOG_ERR(( "fd_bpf_state_encode failed" ));
     567           0 :   }
     568           3 :   fd_memcpy( (uchar *)acc->data+PROGRAMDATA_METADATA_SIZE, elf, elf_sz );
     569             : 
     570           3 :   return acc;
     571           3 : }
     572             : 
     573             : void
     574             : migrate_builtin_to_core_bpf1( fd_core_bpf_migration_config_t const * config,
     575             :                               fd_accdb_t *                           accdb,
     576             :                               fd_bank_t *                            bank,
     577             :                               fd_runtime_stack_t *                   runtime_stack,
     578             :                               fd_pubkey_t const *                    builtin_program_id,
     579           3 :                               fd_capture_ctx_t *                     capture_ctx ) {
     580             : 
     581           3 :   tmp_account_new( &runtime_stack->bpf_migration.program_account, 0UL );
     582             : 
     583           3 :   target_builtin_t target[1];
     584           3 :   if( FD_UNLIKELY( !target_builtin_new_checked(
     585           3 :       target,
     586           3 :       builtin_program_id,
     587           3 :       config->migration_target,
     588           3 :       FD_FEATURE_ACTIVE_BANK( bank, relax_programdata_account_check_migration ),
     589           3 :       accdb,
     590           3 :       bank->accdb_fork_id,
     591           3 :       runtime_stack ) ) )
     592           0 :     return;
     593             : 
     594           3 :   fd_memset( &runtime_stack->bpf_migration.source,                  0, sizeof(runtime_stack->bpf_migration.source                 ) );
     595           3 :   fd_memset( &runtime_stack->bpf_migration.new_target_program,      0, sizeof(runtime_stack->bpf_migration.new_target_program     ) );
     596           3 :   fd_memset( &runtime_stack->bpf_migration.new_target_program_data, 0, sizeof(runtime_stack->bpf_migration.new_target_program_data) );
     597           3 :   fd_memset( &runtime_stack->bpf_migration.empty,                   0, sizeof(runtime_stack->bpf_migration.empty                  ) );
     598           3 :   fd_memset( &runtime_stack->bpf_migration.progcache_validate,      0, sizeof(runtime_stack->bpf_migration.progcache_validate     ) );
     599             : 
     600           3 :   fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
     601           3 :   if( FD_UNLIKELY( !source_buffer_new_checked(
     602           3 :       source,
     603           3 :       accdb,
     604           3 :       bank->accdb_fork_id,
     605           3 :       config->source_buffer_address,
     606           3 :       config->verified_build_hash ) ) )
     607           0 :     return;
     608             : 
     609           3 :   fd_rent_t const * rent = &bank->f.rent;
     610           3 :   ulong const       slot = bank->f.slot;
     611             : 
     612           3 :   fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration.new_target_program;
     613           3 :   if( FD_UNLIKELY( !new_target_program_account(
     614           3 :       new_target_program,
     615           3 :       target,
     616           3 :       rent ) ) )
     617           0 :     return;
     618           3 :   new_target_program->pubkey = *builtin_program_id;
     619             : 
     620           3 :   fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
     621           3 :   if( FD_UNLIKELY( !new_target_program_data_account(
     622           3 :       new_target_program_data,
     623           3 :       source,
     624           3 :       config->upgrade_authority_address,
     625           3 :       rent,
     626           3 :       slot ) ) )
     627           0 :     return;
     628           3 :   new_target_program_data->pubkey = target->program_data_address;
     629             : 
     630           3 :   ulong old_data_sz;
     631           3 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
     632             : 
     633           3 :   ulong new_data_sz;
     634           3 :   if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return;
     635             : 
     636           3 :   FD_DCHECK_CRIT( new_target_program_data->data_sz>=PROGRAMDATA_METADATA_SIZE, "undersize account" );
     637             :   /* FIXME call fd_directly_invoke_loader_v3_deploy */
     638             : 
     639             :   /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L267-L281 */
     640           3 :   ulong lamports_to_burn;
     641           3 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->lamports, source->lamports, &lamports_to_burn ) ) ) return;
     642           3 :   if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) )       return;
     643             : 
     644           3 :   ulong lamports_to_fund;
     645           3 :   if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->lamports, new_target_program_data->lamports, &lamports_to_fund ) ) ) return;
     646             : 
     647             :   /* Write back accounts */
     648           3 :   tmp_account_store( bank, accdb, new_target_program,      capture_ctx, 0 );
     649           3 :   tmp_account_store( bank, accdb, new_target_program_data, capture_ctx, 1 );
     650           3 :   fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
     651           3 :   tmp_account_new( empty, 0UL );
     652           3 :   empty->pubkey = source->pubkey;
     653           3 :   tmp_account_store( bank, accdb, empty, capture_ctx, 0 );
     654             : 
     655             :   /* FIXME "remove the built-in program from the bank's list of builtins" */
     656             :   /* FIXME "update account data size delta" */
     657           3 : }
     658             : 
     659             : /* Mimics migrate_builtin_to_core_bpf().
     660             :    https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#215-303 */
     661             : void
     662             : fd_migrate_builtin_to_core_bpf( fd_bank_t *                            bank,
     663             :                                 fd_accdb_t *                           accdb,
     664             :                                 fd_runtime_stack_t *                   runtime_stack,
     665             :                                 fd_core_bpf_migration_config_t const * config,
     666           3 :                                 fd_capture_ctx_t *                     capture_ctx ) {
     667           3 :   migrate_builtin_to_core_bpf1( config, accdb, bank, runtime_stack, config->builtin_program_id, capture_ctx );
     668           3 : }
     669             : 
     670             : /* Mimics upgrade_core_bpf_program().
     671             :    https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L319-L377 */
     672             : void
     673             : fd_upgrade_core_bpf_program( fd_bank_t *                            bank,
     674             :                              fd_accdb_t *                           accdb,
     675             :                              fd_runtime_stack_t *                   runtime_stack,
     676             :                              fd_pubkey_t const *                    builtin_program_id,
     677             :                              fd_pubkey_t const *                    source_buffer_address,
     678           3 :                              fd_capture_ctx_t *                     capture_ctx ) {
     679           3 :   fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
     680             : 
     681             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L327 */
     682           3 :   target_core_bpf_t target[1];
     683           3 :   if( FD_UNLIKELY( !target_core_bpf_new_checked( target, builtin_program_id, accdb, bank->accdb_fork_id, runtime_stack ) ) ) {
     684           0 :     return;
     685           0 :   }
     686             : 
     687             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L328 */
     688           3 :   fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
     689           3 :   if( FD_UNLIKELY( !source_buffer_new_checked( source, accdb, bank->accdb_fork_id, source_buffer_address, NULL ) ) ) {
     690           0 :     return;
     691           0 :   }
     692             : 
     693             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L118-L125 */
     694           3 :   if( target->has_upgrade_authority_address ) {
     695           3 :     fd_bpf_state_t buffer_state[1];
     696           3 :     if( FD_UNLIKELY( fd_bpf_state_decode( buffer_state, source->data, BUFFER_METADATA_SIZE ) ||
     697           3 :                      buffer_state->discriminant!=FD_BPF_STATE_BUFFER ||
     698           3 :                      !buffer_state->inner.buffer.has_authority_address ||
     699           3 :                      !fd_pubkey_eq( &target->upgrade_authority_address, &buffer_state->inner.buffer.authority_address ) ) ) {
     700             :       /* CoreBpfMigrationError::UpgradeAuthorityMismatch */
     701           0 :       FD_LOG_WARNING(( "core-BPF program upgrade aborted at slot %lu: source buffer authority does not match the target program's upgrade authority",
     702           0 :                        bank->f.slot ));
     703           0 :       return;
     704           0 :     }
     705           3 :   }
     706             : 
     707             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L331-L332  */
     708           3 :   fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
     709           3 :   fd_pubkey_t program_data_address = get_program_data_address( builtin_program_id );
     710             : 
     711           3 :   ulong program_data_len = source->data_sz - BUFFER_METADATA_SIZE;
     712           3 :   ulong new_account_size = PROGRAMDATA_METADATA_SIZE + program_data_len;
     713             : 
     714           3 :   tmp_account_new( new_target_program_data, new_account_size );
     715           3 :   new_target_program_data->pubkey = program_data_address;
     716             : 
     717           3 :   fd_rent_t const * rent = &bank->f.rent;
     718           3 :   new_target_program_data->lamports   = fd_rent_exempt_minimum_balance( rent, new_account_size );
     719           3 :   new_target_program_data->executable = 0;
     720           3 :   fd_memcpy( new_target_program_data->owner.uc, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) );
     721             : 
     722           3 :   fd_bpf_state_t programdata_state[1] = {{
     723           3 :     .discriminant = FD_BPF_STATE_PROGRAM_DATA,
     724           3 :     .inner = { .program_data = {
     725           3 :       .slot = bank->f.slot,
     726           3 :       .upgrade_authority_address = target->upgrade_authority_address,
     727           3 :       .has_upgrade_authority_address = target->has_upgrade_authority_address
     728           3 :     }}
     729           3 :   }};
     730             : 
     731           3 :   ulong out_sz = 0UL;
     732           3 :   if( FD_UNLIKELY( fd_bpf_state_encode( programdata_state, new_target_program_data->data, PROGRAMDATA_METADATA_SIZE, &out_sz ) ) ) {
     733           0 :     return;
     734           0 :   }
     735             : 
     736           3 :   fd_memcpy( new_target_program_data->data + PROGRAMDATA_METADATA_SIZE,
     737           3 :              source->data + BUFFER_METADATA_SIZE,
     738           3 :              program_data_len );
     739             : 
     740             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.4/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L339-L346 */
     741           3 :   ulong old_data_sz;
     742           3 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
     743           3 :   ulong new_data_sz = new_target_program_data->data_sz;
     744             : 
     745             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.4/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L349-L355 */
     746           3 :   uchar const * elf    = new_target_program_data->data + PROGRAMDATA_METADATA_SIZE;
     747           3 :   ulong         elf_sz = program_data_len;
     748           3 :   if( FD_UNLIKELY( fd_directly_invoke_loader_v3_deploy_checks( bank, runtime_stack, elf, elf_sz ) ) ) return;
     749             : 
     750             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L359-L364 */
     751           3 :   ulong lamports_to_burn;
     752           3 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->lamports, source->lamports, &lamports_to_burn ) ) ) return;
     753             : 
     754             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L366-L371 */
     755           3 :   fd_pubkey_t source_addr = source->pubkey;
     756           3 :   tmp_account_store( bank, accdb, new_target_program_data, capture_ctx, 1 );
     757             : 
     758           3 :   fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
     759           3 :   tmp_account_new( empty, 0UL );
     760           3 :   empty->pubkey = source_addr;
     761           3 :   tmp_account_store( bank, accdb, empty, capture_ctx, 0 );
     762             : 
     763             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L374 */
     764             :   /* FIXME "update account data size delta" */
     765           3 :   (void)old_data_sz;
     766           3 :   (void)new_data_sz;
     767             : 
     768           3 :   fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
     769           3 : }
     770             : 
     771             : /* Mimics upgrade_loader_v2_program_with_loader_v3_program().
     772             :    https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L402-L474 */
     773             : void
     774             : fd_upgrade_loader_v2_program_with_loader_v3_program( fd_bank_t *               bank,
     775             :                                                      fd_accdb_t *              accdb,
     776             :                                                      fd_runtime_stack_t *      runtime_stack,
     777             :                                                      fd_pubkey_t const *       loader_v2_program_address,
     778             :                                                      fd_pubkey_t const *       source_buffer_address,
     779             :                                                      int                       allow_prefunded,
     780           0 :                                                      fd_capture_ctx_t *        capture_ctx ) {
     781           0 :   fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
     782             : 
     783             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L411-L412 */
     784           0 :   target_builtin_t target[1];
     785           0 :   if( FD_UNLIKELY( !target_bpf_v2_new_checked(
     786           0 :       target,
     787           0 :       loader_v2_program_address,
     788           0 :       allow_prefunded,
     789           0 :       accdb,
     790           0 :       bank->accdb_fork_id,
     791           0 :       runtime_stack ) ) )
     792           0 :     return;
     793             : 
     794             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L413 */
     795           0 :   fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
     796           0 :   if( FD_UNLIKELY( !source_buffer_new_checked( source, accdb, bank->accdb_fork_id, source_buffer_address, NULL ) ) )
     797           0 :     return;
     798             : 
     799           0 :   fd_rent_t const * rent = &bank->f.rent;
     800           0 :   ulong             slot = bank->f.slot;
     801             : 
     802             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L416-L417 */
     803           0 :   fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration.new_target_program;
     804           0 :   if( FD_UNLIKELY( !new_target_program_account( new_target_program, target, rent ) ) )
     805           0 :     return;
     806           0 :   new_target_program->pubkey = *loader_v2_program_address;
     807             : 
     808             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L419-L421 */
     809           0 :   fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
     810           0 :   if( FD_UNLIKELY( !new_target_program_data_account( new_target_program_data, source, NULL, rent, slot ) ) ) {
     811           0 :     return;
     812           0 :   }
     813           0 :   new_target_program_data->pubkey = target->program_data_address;
     814             : 
     815             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L427-L435 */
     816           0 :   ulong old_data_sz;
     817           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
     818             : 
     819             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L432-L435 */
     820           0 :   ulong new_data_sz;
     821           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return;
     822             : 
     823           0 :   if( FD_UNLIKELY( new_target_program_data->data_sz<PROGRAMDATA_METADATA_SIZE ) ) {
     824           0 :     FD_LOG_CRIT(( "invariant violation: new target programdata too small" ));
     825           0 :   }
     826             : 
     827             :   /* Agave calls directly_invoke_loader_v3_deploy to deploy the new
     828             :      program to the program cache. We don't do that, but instead we
     829             :      perform the same checks as directly_invoke_loader_v3_deploy
     830             :      without modifying the program cache. We need to do the checks
     831             :      at this point so that we can fail the upgrade if the ELF is
     832             :      invalid.
     833             : 
     834             :      This is safe because the bpf migration code runs at the epoch
     835             :      boundary, before any transaction execution. The program cache
     836             :      automatically invalidates all programs at the start of an epoch
     837             :      boundary, so we do not need to explicitly update the cache during the
     838             :      migration.
     839             : 
     840             :      https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L437-L443*/
     841           0 :   uchar const * elf    = (uchar const *)new_target_program_data->data + PROGRAMDATA_METADATA_SIZE;
     842           0 :   ulong         elf_sz = new_target_program_data->data_sz - PROGRAMDATA_METADATA_SIZE;
     843           0 :   if( FD_UNLIKELY( fd_directly_invoke_loader_v3_deploy_checks( bank, runtime_stack, elf, elf_sz ) ) ) return;
     844             : 
     845             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L451-L459 */
     846           0 :   ulong lamports_to_burn;
     847           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->lamports, source->lamports, &lamports_to_burn ) ) ) return;
     848           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) )       return;
     849             : 
     850           0 :   ulong lamports_to_fund;
     851           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->lamports, new_target_program_data->lamports, &lamports_to_fund ) ) ) return;
     852             : 
     853             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L462-L468 */
     854           0 :   tmp_account_store( bank, accdb, new_target_program,      capture_ctx, 0 );
     855           0 :   tmp_account_store( bank, accdb, new_target_program_data, capture_ctx, 1 );
     856             : 
     857           0 :   fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
     858           0 :   tmp_account_new( empty, 0UL );
     859           0 :   empty->pubkey = source->pubkey;
     860           0 :   tmp_account_store( bank, accdb, empty, capture_ctx, 0 );
     861             : 
     862             :   /* NB: Agave updates "delta_off_chain", using these two fields,
     863             :      which is not consensus-critical (only used for Agave stats)
     864             :      so we don't update this in our migration code or store this in
     865             :      our bank. */
     866           0 :   (void)old_data_sz;
     867           0 :   (void)new_data_sz;
     868             : 
     869           0 :   fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
     870           0 : }

Generated by: LCOV version 1.14