LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_core_bpf_migration.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 85 531 16.0 %
Date: 2026-11-11 12:40:43 Functions: 7 15 46.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          28 : get_program_data_address( fd_pubkey_t const * program_addr ) {
      16          28 :   uchar const * seed    = program_addr->uc;
      17          28 :   ulong         seed_sz = 32UL;
      18          28 :   fd_pubkey_t   out;
      19          28 :   uint          custom_err;
      20          28 :   uchar         out_bump_seed;
      21          28 :   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          28 :   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          28 :   return out;
      27          28 : }
      28             : 
      29             : fd_tmp_account_t *
      30             : tmp_account_new( fd_tmp_account_t * acc,
      31          28 :                  ulong              acc_sz ) {
      32          28 :   acc->data_sz = acc_sz;
      33          28 :   fd_memset( acc->data,  0, acc_sz );
      34          28 :   acc->lamports = 0UL;
      35          28 :   acc->executable = 0;
      36          28 :   fd_memset( acc->owner.uc, 0, 32UL );
      37          28 :   fd_memset( acc->pubkey.uc, 0, 32UL );
      38          28 :   return acc;
      39          28 : }
      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          28 :                   fd_pubkey_t const *       addr ) {
      46          28 :   fd_acc_t db_acc = fd_accdb_read_one( accdb, fork_id, addr->uc );
      47          28 :   if( FD_UNLIKELY( !db_acc.lamports ) ) {
      48          28 :     fd_accdb_unread_one( accdb, &db_acc );
      49          28 :     return NULL;
      50          28 :   }
      51             : 
      52           0 :   acc->lamports = db_acc.lamports;
      53           0 :   fd_memcpy( acc->owner.uc, db_acc.owner, 32UL );
      54           0 :   acc->executable = db_acc.executable;
      55           0 :   fd_memcpy( acc->data, db_acc.data, db_acc.data_len );
      56           0 :   acc->data_sz = db_acc.data_len;
      57           0 :   acc->pubkey = *addr;
      58             : 
      59           0 :   fd_accdb_unread_one( accdb, &db_acc );
      60           0 :   return acc;
      61          28 : }
      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           0 :                    int                pd_write ) {
      72           0 :   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           0 :   fd_accdb_svm_update_t update[1];
      75           0 :   fd_acc_t db_acc = fd_accdb_svm_open_rw( bank, accdb, update, &acc->pubkey, 1 );
      76             : 
      77           0 :   db_acc.executable = acc->executable;
      78           0 :   fd_memcpy( db_acc.owner, acc->owner.uc, 32UL );
      79           0 :   db_acc.lamports = acc->lamports;
      80           0 :   fd_memcpy( db_acc.data, acc->data, acc->data_sz );
      81           0 :   db_acc.data_len = acc->data_sz;
      82           0 :   db_acc.pd_write = pd_write;
      83             : 
      84           0 :   fd_accdb_svm_close_rw( bank, accdb, capture_ctx, &db_acc, update );
      85           0 : }
      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          28 :                             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          28 :   fd_tmp_account_t * program_account = &runtime_stack->bpf_migration->program_account;
     122          28 :   switch( migration_target ) {
     123           0 :   case FD_CORE_BPF_MIGRATION_TARGET_BUILTIN:
     124           0 :     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           0 :     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           0 :     break;
     133          28 :   case FD_CORE_BPF_MIGRATION_TARGET_STATELESS: {
     134             :     /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
     135          28 :     if( FD_UNLIKELY( fd_accdb_exists( accdb, fork_id, program_address->uc ) ) ) return NULL;
     136          28 :     break;
     137          28 :   }
     138          28 :   default:
     139           0 :     FD_LOG_ERR(( "invalid migration_target %d", migration_target ));
     140          28 :   }
     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          28 :   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          28 :   ulong program_data_account_lamports = 0UL;
     149          28 :   do {
     150             :     /* Program data account should not exist */
     151          28 :     fd_acc_t progdata = fd_accdb_read_one( accdb, fork_id, program_data_address.uc );
     152          28 :     int progdata_exists = !!progdata.lamports;
     153          28 :     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          28 :     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          26 :       if( FD_UNLIKELY( progdata_exists ) ) {
     161           0 :         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           0 :         } else {
     166           0 :           program_data_account_lamports = progdata.lamports;
     167           0 :           fd_accdb_unread_one( accdb, &progdata );
     168           0 :         }
     169           0 :       }
     170          26 :     } 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           2 :       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           2 :     }
     179          28 :   } 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          28 :   *target_builtin = (target_builtin_t) {
     184          28 :     .program_account               = program_account,
     185          28 :     .program_data_address          = program_data_address,
     186          28 :     .program_data_account_lamports = program_data_account_lamports
     187          28 :   };
     188          28 :   return target_builtin;
     189          28 : }
     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           0 :                              fd_runtime_stack_t * runtime_stack ) {
     198           0 :   fd_pubkey_t program_data_address = get_program_data_address( program_address );
     199             : 
     200             :   /* The program account should exist */
     201           0 :   fd_tmp_account_t * program_account = &runtime_stack->bpf_migration->program_account;
     202           0 :   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           0 :   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           0 :   if( FD_UNLIKELY( !program_account->executable ) ) {
     213           0 :     return NULL;
     214           0 :   }
     215             : 
     216             :   /* Decode and validate program account state */
     217           0 :   fd_bpf_state_t program_state[1];
     218           0 :   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           0 :   if( FD_UNLIKELY( program_state->discriminant!=FD_BPF_STATE_PROGRAM ) ) {
     222           0 :     return NULL;
     223           0 :   }
     224           0 :   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           0 :   fd_tmp_account_t * program_data_account = &runtime_stack->bpf_migration->new_target_program;
     230           0 :   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           0 :   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           0 :   fd_bpf_state_t programdata_state[1];
     241           0 :   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           0 :   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           0 :   fd_pubkey_t upgrade_authority_address;
     250           0 :   if( programdata_state->inner.program_data.has_upgrade_authority_address ) {
     251           0 :     upgrade_authority_address = programdata_state->inner.program_data.upgrade_authority_address;
     252           0 :   } else {
     253           0 :     fd_memset( &upgrade_authority_address, 0, sizeof(fd_pubkey_t) );
     254           0 :   }
     255             : 
     256           0 :   *target_core_bpf = (target_core_bpf_t) {
     257           0 :     .program_address                = *program_address,
     258           0 :     .program_data_account           = program_data_account,
     259           0 :     .upgrade_authority_address      = upgrade_authority_address,
     260           0 :     .has_upgrade_authority_address  = (uint)!!programdata_state->inner.program_data.has_upgrade_authority_address
     261           0 :   };
     262           0 :   return target_core_bpf;
     263           0 : }
     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 when the migration feature activates, before transaction
     349             :    execution.  The feature activation selects a new program-cache
     350             :    revision, so no explicit cache update is needed here.
     351             : 
     352             :    https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L120-L218 */
     353             : static int
     354             : fd_directly_invoke_loader_v3_deploy_checks( fd_bank_t const *    bank,
     355             :                                             fd_runtime_stack_t * runtime_stack,
     356             :                                             uchar const *        elf,
     357           0 :                                             ulong                elf_sz ) {
     358           0 :   fd_features_t const * features = &bank->f.features;
     359           0 :   ulong                 slot     = bank->f.slot;
     360             : 
     361             :   /* ELF verification with deploy checks enabled */
     362           0 :   fd_prog_versions_t versions = fd_prog_versions( features, slot );
     363           0 :   fd_sbpf_loader_config_t loader_config = {
     364           0 :     .elf_deploy_checks = 1,
     365           0 :     .sbpf_min_version  = versions.min_sbpf_version,
     366           0 :     .sbpf_max_version  = versions.max_sbpf_version,
     367           0 :   };
     368           0 :   fd_sbpf_elf_info_t elf_info[1];
     369           0 :   if( FD_UNLIKELY( fd_sbpf_elf_peek( elf_info, elf, elf_sz, &loader_config )!=FD_SBPF_ELF_SUCCESS ) ) return 1;
     370             : 
     371             :   /* Setup program (includes calldests) */
     372           0 :   fd_sbpf_program_t * prog = fd_sbpf_program_new(
     373           0 :     runtime_stack->bpf_migration->progcache_validate.sbpf_footprint,
     374           0 :     elf_info,
     375           0 :     runtime_stack->bpf_migration->progcache_validate.rodata );
     376           0 :   if( FD_UNLIKELY( !prog ) ) return 1;
     377             : 
     378           0 :   fd_sbpf_syscalls_t _syscalls[ FD_SBPF_SYSCALLS_SLOT_CNT ];
     379           0 :   fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_join( fd_sbpf_syscalls_new( _syscalls ) );
     380           0 :   if( FD_UNLIKELY( !syscalls ) ) return 1;
     381           0 :   if( FD_UNLIKELY( fd_vm_syscall_register_slot( syscalls, slot, features, /* is_deploy */ 1 )!=FD_VM_SUCCESS ) ) return 1;
     382             : 
     383             :   /* fd_sbpf_program_load checks */
     384           0 :   if( FD_UNLIKELY( fd_sbpf_program_load(
     385           0 :     prog,
     386           0 :     elf,
     387           0 :     elf_sz,
     388           0 :     syscalls,
     389           0 :     &loader_config,
     390           0 :     runtime_stack->bpf_migration->progcache_validate.programdata,
     391           0 :     sizeof(runtime_stack->bpf_migration->progcache_validate.programdata) ) ) ) return 1;
     392             : 
     393             :   /* fd_vm_validate checks */
     394           0 :   fd_vm_t _vm[1];
     395           0 :   fd_vm_t * vm = fd_vm_join( fd_vm_new( _vm ) );
     396           0 :   if( FD_UNLIKELY( !vm ) ) return 1;
     397           0 :   vm = fd_vm_init( vm,
     398           0 :                    NULL,
     399           0 :                    0UL,
     400           0 :                    0UL,
     401           0 :                    prog->rodata,
     402           0 :                    prog->rodata_sz,
     403           0 :                    prog->text,
     404           0 :                    prog->info.text_cnt,
     405           0 :                    prog->info.text_off,
     406           0 :                    prog->info.text_sz,
     407           0 :                    prog->entry_pc,
     408           0 :                    prog->calldests,
     409           0 :                    elf_info->sbpf_version,
     410           0 :                    syscalls,
     411           0 :                    NULL,
     412           0 :                    NULL,
     413           0 :                    NULL,
     414           0 :                    0U,
     415           0 :                    NULL,
     416           0 :                    0,
     417           0 :                    FD_FEATURE_ACTIVE( slot, features, account_data_direct_mapping ),
     418           0 :                    FD_FEATURE_ACTIVE( slot, features, syscall_parameter_address_restrictions ),
     419           0 :                    FD_FEATURE_ACTIVE( slot, features, virtual_address_space_adjustments ),
     420           0 :                    0,
     421           0 :                    0UL );
     422           0 :   if( FD_UNLIKELY( !vm ) ) return 1;
     423           0 :   if( FD_UNLIKELY( fd_vm_validate( vm )!=FD_VM_SUCCESS ) ) return 1;
     424             : 
     425           0 :   return FD_EXECUTOR_INSTR_SUCCESS;
     426           0 : }
     427             : 
     428             : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L51-L75 */
     429             : 
     430             : static fd_tmp_account_t *
     431             : source_buffer_new_checked( fd_tmp_account_t *  acc,
     432             :                            fd_accdb_t *        accdb,
     433             :                            fd_accdb_fork_id_t  fork_id,
     434             :                            fd_pubkey_t const * pubkey,
     435          28 :                            fd_hash_t const *   verified_build_hash ) {
     436             : 
     437          28 :   if( FD_UNLIKELY( !tmp_account_read( acc, accdb, fork_id, pubkey ) ) ) {
     438             :     /* CoreBpfMigrationError::AccountNotFound(*buffer_address) */
     439          28 :     return NULL;
     440          28 :   }
     441             : 
     442           0 :   if( FD_UNLIKELY( 0!=memcmp( acc->owner.uc, &fd_solana_bpf_loader_upgradeable_program_id, 32 ) ) ) {
     443             :     /* CoreBpfMigrationError::IncorrectOwner(*buffer_address) */
     444           0 :     return NULL;
     445           0 :   }
     446             : 
     447           0 :   if( acc->data_sz < BUFFER_METADATA_SIZE ) {
     448             :     /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
     449           0 :     return NULL;
     450           0 :   }
     451             : 
     452           0 :   fd_bpf_state_t state[1];
     453           0 :   if( FD_UNLIKELY( fd_bpf_state_decode( state, acc->data, BUFFER_METADATA_SIZE ) ) ) {
     454           0 :     return NULL;
     455           0 :   }
     456             : 
     457           0 :   if( FD_UNLIKELY( state->discriminant!=FD_BPF_STATE_BUFFER ) ) {
     458             :     /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
     459           0 :     return NULL;
     460           0 :   }
     461             : 
     462             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L71 */
     463           0 :   if( verified_build_hash ) {
     464             :     /* Strip trailing zero-padding before hashing
     465             :        https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L63 */
     466           0 :     uchar const * data       = (uchar const *)acc->data;
     467           0 :     ulong         offset     = BUFFER_METADATA_SIZE;
     468           0 :     ulong         end_offset = acc->data_sz;
     469           0 :     while( end_offset>offset && data[end_offset-1]==0 ) end_offset--;
     470           0 :     uchar const * buffer_program_data    = data + offset;
     471           0 :     ulong         buffer_program_data_sz = end_offset - offset;
     472             : 
     473           0 :     fd_hash_t hash;
     474           0 :     fd_sha256_hash( buffer_program_data, buffer_program_data_sz, hash.uc );
     475           0 :     if( FD_UNLIKELY( 0!=memcmp( hash.uc, verified_build_hash->uc, FD_HASH_FOOTPRINT ) ) ) {
     476             :       /* CoreBpfMigrationError::BuildHashMismatch */
     477           0 :       return NULL;
     478           0 :     }
     479           0 :   }
     480             : 
     481           0 :   return acc;
     482           0 : }
     483             : 
     484             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L82-L95 */
     485             : 
     486             : static fd_tmp_account_t *
     487             : new_target_program_account( fd_tmp_account_t *        acc,
     488             :                             target_builtin_t const *  target,
     489           0 :                             fd_rent_t const *         rent ) {
     490             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L86-L88 */
     491           0 :   fd_bpf_state_t state = {
     492           0 :     .discriminant = FD_BPF_STATE_PROGRAM,
     493           0 :     .inner = {
     494           0 :       .program = {
     495           0 :         .programdata_address = target->program_data_address,
     496           0 :       }
     497           0 :     }
     498           0 :   };
     499             : 
     500           0 :   ulong state_sz = fd_bpf_state_size( &state );
     501           0 :   tmp_account_new( acc, state_sz );
     502           0 :   acc->lamports   = fd_rent_exempt_minimum_balance( rent, SIZE_OF_PROGRAM );
     503           0 :   acc->executable = 1;
     504           0 :   memcpy( acc->owner.uc, fd_solana_bpf_loader_upgradeable_program_id.uc, sizeof(fd_pubkey_t) );
     505             : 
     506           0 :   ulong out_sz = 0UL;
     507           0 :   if( FD_UNLIKELY( fd_bpf_state_encode( &state, acc->data, state_sz, &out_sz ) ) ) {
     508           0 :     FD_LOG_ERR(( "fd_bpf_state_encode failed" ));
     509           0 :   }
     510             : 
     511           0 :   return acc;
     512           0 : }
     513             : 
     514             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L108-L153 */
     515             : static fd_tmp_account_t *
     516             : new_target_program_data_account( fd_tmp_account_t *       acc,
     517             :                                  fd_tmp_account_t const * source,
     518             :                                  fd_pubkey_t const *      upgrade_authority_address,
     519             :                                  fd_rent_t const *        rent,
     520           0 :                                  ulong                    slot ) {
     521           0 :   ulong const buffer_metadata_sz = BUFFER_METADATA_SIZE;
     522             : 
     523           0 :   if( FD_UNLIKELY( source->data_sz < buffer_metadata_sz ) )
     524           0 :     return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
     525             : 
     526           0 :   fd_bpf_state_t state;
     527           0 :   if( FD_UNLIKELY( fd_bpf_state_decode( &state, source->data, buffer_metadata_sz ) ) ) {
     528           0 :     return NULL;
     529           0 :   }
     530             : 
     531           0 :   if( FD_UNLIKELY( state.discriminant!=FD_BPF_STATE_BUFFER ) )
     532           0 :     return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
     533             : 
     534             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L118-L125 */
     535           0 :   if( upgrade_authority_address ) {
     536           0 :     if( FD_UNLIKELY( !state.inner.buffer.has_authority_address ||
     537           0 :                      !fd_pubkey_eq( upgrade_authority_address, &state.inner.buffer.authority_address ) ) ) {
     538           0 :       return NULL; /* CoreBpfMigrationError::UpgradeAuthorityMismatch */
     539           0 :     }
     540           0 :   }
     541             : 
     542           0 :   void const * elf      = (uchar const *)source->data    + buffer_metadata_sz;
     543           0 :   ulong        elf_sz   = /*           */source->data_sz - buffer_metadata_sz;
     544             : 
     545           0 :   ulong        space    = PROGRAMDATA_METADATA_SIZE + elf_sz;
     546           0 :   ulong        lamports = fd_rent_exempt_minimum_balance( rent, space );
     547           0 :   fd_pubkey_t  owner    = fd_solana_bpf_loader_upgradeable_program_id;
     548             : 
     549           0 :   fd_bpf_state_t programdata_meta = {
     550           0 :     .discriminant = FD_BPF_STATE_PROGRAM_DATA,
     551           0 :     .inner = {
     552           0 :       .program_data = {
     553           0 :         .slot = slot,
     554           0 :         .has_upgrade_authority_address = !!upgrade_authority_address,
     555           0 :         .upgrade_authority_address     = upgrade_authority_address ? *upgrade_authority_address : (fd_pubkey_t){{0}}
     556           0 :       }
     557           0 :     }
     558           0 :   };
     559             : 
     560           0 :   tmp_account_new( acc, space );
     561           0 :   acc->lamports = lamports;
     562           0 :   memcpy( acc->owner.uc, owner.uc, sizeof(fd_pubkey_t) );
     563           0 :   ulong out_sz = 0UL;
     564           0 :   if( FD_UNLIKELY( fd_bpf_state_encode( &programdata_meta, acc->data, PROGRAMDATA_METADATA_SIZE, &out_sz ) ) ) {
     565           0 :     FD_LOG_ERR(( "fd_bpf_state_encode failed" ));
     566           0 :   }
     567           0 :   fd_memcpy( (uchar *)acc->data+PROGRAMDATA_METADATA_SIZE, elf, elf_sz );
     568             : 
     569           0 :   return acc;
     570           0 : }
     571             : 
     572             : void
     573             : migrate_builtin_to_core_bpf1( fd_core_bpf_migration_config_t const * config,
     574             :                               fd_accdb_t *                           accdb,
     575             :                               fd_bank_t *                            bank,
     576             :                               fd_runtime_stack_t *                   runtime_stack,
     577             :                               fd_pubkey_t const *                    builtin_program_id,
     578          28 :                               fd_capture_ctx_t *                     capture_ctx ) {
     579             : 
     580          28 :   tmp_account_new( &runtime_stack->bpf_migration->program_account, 0UL );
     581             : 
     582          28 :   target_builtin_t target[1];
     583          28 :   if( FD_UNLIKELY( !target_builtin_new_checked(
     584          28 :       target,
     585          28 :       builtin_program_id,
     586          28 :       config->migration_target,
     587          28 :       FD_FEATURE_ACTIVE_BANK( bank, relax_programdata_account_check_migration ),
     588          28 :       accdb,
     589          28 :       bank->accdb_fork_id,
     590          28 :       runtime_stack ) ) )
     591           0 :     return;
     592             : 
     593          28 :   fd_memset( &runtime_stack->bpf_migration->source,                  0, sizeof(runtime_stack->bpf_migration->source                 ) );
     594          28 :   fd_memset( &runtime_stack->bpf_migration->new_target_program,      0, sizeof(runtime_stack->bpf_migration->new_target_program     ) );
     595          28 :   fd_memset( &runtime_stack->bpf_migration->new_target_program_data, 0, sizeof(runtime_stack->bpf_migration->new_target_program_data) );
     596          28 :   fd_memset( &runtime_stack->bpf_migration->empty,                   0, sizeof(runtime_stack->bpf_migration->empty                  ) );
     597          28 :   fd_memset( &runtime_stack->bpf_migration->progcache_validate,      0, sizeof(runtime_stack->bpf_migration->progcache_validate     ) );
     598             : 
     599             :   /* https://github.com/anza-xyz/agave/blob/8da849e919e0762f6bfc9ca17ac2339c7a003a0e/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L232-L240 */
     600          28 :   fd_tmp_account_t * source = &runtime_stack->bpf_migration->source;
     601          28 :   if( FD_UNLIKELY( !source_buffer_new_checked(
     602          28 :       source,
     603          28 :       accdb,
     604          28 :       bank->accdb_fork_id,
     605          28 :       config->source_buffer_address,
     606          28 :       config->verified_build_hash ) ) )
     607          28 :     return;
     608             :   /* This should never happen after core_bpf_hash_validation is
     609             :      activated, which is a pre-req for all future BPF program upgrades. */
     610           0 :   if( FD_UNLIKELY( !config->verified_build_hash ) ) {
     611           0 :     FD_BASE58_ENCODE_32_BYTES( config->source_buffer_address->uc, buffer_b58 );
     612           0 :     FD_LOG_ERR(( "missing verified build hash for source buffer %s", buffer_b58 ));
     613           0 :   }
     614             : 
     615           0 :   fd_rent_t const * rent = &bank->f.rent;
     616           0 :   ulong const       slot = bank->f.slot;
     617             : 
     618           0 :   fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration->new_target_program;
     619           0 :   if( FD_UNLIKELY( !new_target_program_account(
     620           0 :       new_target_program,
     621           0 :       target,
     622           0 :       rent ) ) )
     623           0 :     return;
     624           0 :   new_target_program->pubkey = *builtin_program_id;
     625             : 
     626           0 :   fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration->new_target_program_data;
     627           0 :   if( FD_UNLIKELY( !new_target_program_data_account(
     628           0 :       new_target_program_data,
     629           0 :       source,
     630           0 :       config->upgrade_authority_address,
     631           0 :       rent,
     632           0 :       slot ) ) )
     633           0 :     return;
     634           0 :   new_target_program_data->pubkey = target->program_data_address;
     635             : 
     636           0 :   ulong old_data_sz;
     637           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
     638             : 
     639           0 :   ulong new_data_sz;
     640           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return;
     641             : 
     642           0 :   FD_DCHECK_CRIT( new_target_program_data->data_sz>=PROGRAMDATA_METADATA_SIZE, "undersize account" );
     643             :   /* FIXME call fd_directly_invoke_loader_v3_deploy */
     644             : 
     645             :   /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L267-L281 */
     646           0 :   ulong lamports_to_burn;
     647           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->lamports, source->lamports, &lamports_to_burn ) ) ) return;
     648           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) )       return;
     649             : 
     650           0 :   ulong lamports_to_fund;
     651           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->lamports, new_target_program_data->lamports, &lamports_to_fund ) ) ) return;
     652             : 
     653             :   /* Write back accounts */
     654           0 :   tmp_account_store( bank, accdb, new_target_program,      capture_ctx, 0 );
     655           0 :   tmp_account_store( bank, accdb, new_target_program_data, capture_ctx, 1 );
     656           0 :   fd_tmp_account_t * empty = &runtime_stack->bpf_migration->empty;
     657           0 :   tmp_account_new( empty, 0UL );
     658           0 :   empty->pubkey = source->pubkey;
     659           0 :   tmp_account_store( bank, accdb, empty, capture_ctx, 0 );
     660             : 
     661             :   /* FIXME "remove the built-in program from the bank's list of builtins" */
     662             :   /* FIXME "update account data size delta" */
     663           0 : }
     664             : 
     665             : /* Mimics migrate_builtin_to_core_bpf().
     666             :    https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#215-303 */
     667             : void
     668             : fd_migrate_builtin_to_core_bpf( fd_bank_t *                            bank,
     669             :                                 fd_accdb_t *                           accdb,
     670             :                                 fd_runtime_stack_t *                   runtime_stack,
     671             :                                 fd_core_bpf_migration_config_t const * config,
     672          28 :                                 fd_capture_ctx_t *                     capture_ctx ) {
     673          28 :   migrate_builtin_to_core_bpf1( config, accdb, bank, runtime_stack, config->builtin_program_id, capture_ctx );
     674          28 : }
     675             : 
     676             : /* Mimics upgrade_core_bpf_program().
     677             :    https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L319-L377 */
     678             : void
     679             : fd_upgrade_core_bpf_program( fd_bank_t *                            bank,
     680             :                              fd_accdb_t *                           accdb,
     681             :                              fd_runtime_stack_t *                   runtime_stack,
     682             :                              fd_pubkey_t const *                    builtin_program_id,
     683             :                              fd_pubkey_t const *                    source_buffer_address,
     684             :                              fd_hash_t const *                      verified_build_hash,
     685           0 :                              fd_capture_ctx_t *                     capture_ctx ) {
     686           0 :   fd_memset( runtime_stack->bpf_migration, 0, sizeof(fd_runtime_stack_bpf_migration_t) );
     687             : 
     688             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L327 */
     689           0 :   target_core_bpf_t target[1];
     690           0 :   if( FD_UNLIKELY( !target_core_bpf_new_checked( target, builtin_program_id, accdb, bank->accdb_fork_id, runtime_stack ) ) ) {
     691           0 :     return;
     692           0 :   }
     693             : 
     694             :   /* https://github.com/anza-xyz/agave/blob/8da849e919e0762f6bfc9ca17ac2339c7a003a0e/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L330-L338 */
     695           0 :   fd_tmp_account_t * source = &runtime_stack->bpf_migration->source;
     696           0 :   if( FD_UNLIKELY( !source_buffer_new_checked(
     697           0 :       source,
     698           0 :       accdb,
     699           0 :       bank->accdb_fork_id,
     700           0 :       source_buffer_address,
     701           0 :       verified_build_hash ) ) ) {
     702           0 :     return;
     703           0 :   }
     704             : 
     705             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L118-L125 */
     706           0 :   if( target->has_upgrade_authority_address ) {
     707           0 :     fd_bpf_state_t buffer_state[1];
     708           0 :     if( FD_UNLIKELY( fd_bpf_state_decode( buffer_state, source->data, BUFFER_METADATA_SIZE ) ||
     709           0 :                      buffer_state->discriminant!=FD_BPF_STATE_BUFFER ||
     710           0 :                      !buffer_state->inner.buffer.has_authority_address ||
     711           0 :                      !fd_pubkey_eq( &target->upgrade_authority_address, &buffer_state->inner.buffer.authority_address ) ) ) {
     712             :       /* CoreBpfMigrationError::UpgradeAuthorityMismatch */
     713           0 :       FD_LOG_WARNING(( "core-BPF program upgrade aborted at slot %lu: source buffer authority does not match the target program's upgrade authority",
     714           0 :                        bank->f.slot ));
     715           0 :       return;
     716           0 :     }
     717           0 :   }
     718             : 
     719             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L331-L332  */
     720           0 :   fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration->new_target_program_data;
     721           0 :   fd_pubkey_t program_data_address = get_program_data_address( builtin_program_id );
     722             : 
     723           0 :   ulong program_data_len = source->data_sz - BUFFER_METADATA_SIZE;
     724           0 :   ulong new_account_size = PROGRAMDATA_METADATA_SIZE + program_data_len;
     725             : 
     726           0 :   tmp_account_new( new_target_program_data, new_account_size );
     727           0 :   new_target_program_data->pubkey = program_data_address;
     728             : 
     729           0 :   fd_rent_t const * rent = &bank->f.rent;
     730           0 :   new_target_program_data->lamports   = fd_rent_exempt_minimum_balance( rent, new_account_size );
     731           0 :   new_target_program_data->executable = 0;
     732           0 :   fd_memcpy( new_target_program_data->owner.uc, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) );
     733             : 
     734           0 :   fd_bpf_state_t programdata_state[1] = {{
     735           0 :     .discriminant = FD_BPF_STATE_PROGRAM_DATA,
     736           0 :     .inner = { .program_data = {
     737           0 :       .slot = bank->f.slot,
     738           0 :       .upgrade_authority_address = target->upgrade_authority_address,
     739           0 :       .has_upgrade_authority_address = target->has_upgrade_authority_address
     740           0 :     }}
     741           0 :   }};
     742             : 
     743           0 :   ulong out_sz = 0UL;
     744           0 :   if( FD_UNLIKELY( fd_bpf_state_encode( programdata_state, new_target_program_data->data, PROGRAMDATA_METADATA_SIZE, &out_sz ) ) ) {
     745           0 :     return;
     746           0 :   }
     747             : 
     748           0 :   fd_memcpy( new_target_program_data->data + PROGRAMDATA_METADATA_SIZE,
     749           0 :              source->data + BUFFER_METADATA_SIZE,
     750           0 :              program_data_len );
     751             : 
     752             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.4/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L339-L346 */
     753           0 :   ulong old_data_sz;
     754           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
     755           0 :   ulong new_data_sz = new_target_program_data->data_sz;
     756             : 
     757             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.4/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L349-L355 */
     758           0 :   uchar const * elf    = new_target_program_data->data + PROGRAMDATA_METADATA_SIZE;
     759           0 :   ulong         elf_sz = program_data_len;
     760           0 :   if( FD_UNLIKELY( fd_directly_invoke_loader_v3_deploy_checks( bank, runtime_stack, elf, elf_sz ) ) ) return;
     761             : 
     762             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L359-L364 */
     763           0 :   ulong lamports_to_burn;
     764           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->lamports, source->lamports, &lamports_to_burn ) ) ) return;
     765             : 
     766             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L366-L371 */
     767           0 :   fd_pubkey_t source_addr = source->pubkey;
     768           0 :   tmp_account_store( bank, accdb, new_target_program_data, capture_ctx, 1 );
     769             : 
     770           0 :   fd_tmp_account_t * empty = &runtime_stack->bpf_migration->empty;
     771           0 :   tmp_account_new( empty, 0UL );
     772           0 :   empty->pubkey = source_addr;
     773           0 :   tmp_account_store( bank, accdb, empty, capture_ctx, 0 );
     774             : 
     775             :   /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L374 */
     776             :   /* FIXME "update account data size delta" */
     777           0 :   (void)old_data_sz;
     778           0 :   (void)new_data_sz;
     779             : 
     780           0 :   fd_memset( runtime_stack->bpf_migration, 0, sizeof(fd_runtime_stack_bpf_migration_t) );
     781           0 : }
     782             : 
     783             : /* Mimics upgrade_loader_v2_program_with_loader_v3_program().
     784             :    https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L402-L474 */
     785             : void
     786             : fd_upgrade_loader_v2_program_with_loader_v3_program( fd_bank_t *               bank,
     787             :                                                      fd_accdb_t *              accdb,
     788             :                                                      fd_runtime_stack_t *      runtime_stack,
     789             :                                                      fd_pubkey_t const *       loader_v2_program_address,
     790             :                                                      fd_pubkey_t const *       source_buffer_address,
     791             :                                                      fd_hash_t const *         verified_build_hash,
     792             :                                                      int                       allow_prefunded,
     793           0 :                                                      fd_capture_ctx_t *        capture_ctx ) {
     794           0 :   fd_memset( runtime_stack->bpf_migration, 0, sizeof(fd_runtime_stack_bpf_migration_t) );
     795             : 
     796             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L411-L412 */
     797           0 :   target_builtin_t target[1];
     798           0 :   if( FD_UNLIKELY( !target_bpf_v2_new_checked(
     799           0 :       target,
     800           0 :       loader_v2_program_address,
     801           0 :       allow_prefunded,
     802           0 :       accdb,
     803           0 :       bank->accdb_fork_id,
     804           0 :       runtime_stack ) ) )
     805           0 :     return;
     806             : 
     807             :   /* https://github.com/anza-xyz/agave/blob/8da849e919e0762f6bfc9ca17ac2339c7a003a0e/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L420-L428 */
     808           0 :   fd_tmp_account_t * source = &runtime_stack->bpf_migration->source;
     809           0 :   if( FD_UNLIKELY( !source_buffer_new_checked(
     810           0 :       source,
     811           0 :       accdb,
     812           0 :       bank->accdb_fork_id,
     813           0 :       source_buffer_address,
     814           0 :       verified_build_hash ) ) )
     815           0 :     return;
     816             : 
     817           0 :   fd_rent_t const * rent = &bank->f.rent;
     818           0 :   ulong             slot = bank->f.slot;
     819             : 
     820             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L416-L417 */
     821           0 :   fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration->new_target_program;
     822           0 :   if( FD_UNLIKELY( !new_target_program_account( new_target_program, target, rent ) ) )
     823           0 :     return;
     824           0 :   new_target_program->pubkey = *loader_v2_program_address;
     825             : 
     826             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L419-L421 */
     827           0 :   fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration->new_target_program_data;
     828           0 :   if( FD_UNLIKELY( !new_target_program_data_account( new_target_program_data, source, NULL, rent, slot ) ) ) {
     829           0 :     return;
     830           0 :   }
     831           0 :   new_target_program_data->pubkey = target->program_data_address;
     832             : 
     833             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L427-L435 */
     834           0 :   ulong old_data_sz;
     835           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
     836             : 
     837             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L432-L435 */
     838           0 :   ulong new_data_sz;
     839           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return;
     840             : 
     841           0 :   if( FD_UNLIKELY( new_target_program_data->data_sz<PROGRAMDATA_METADATA_SIZE ) ) {
     842           0 :     FD_LOG_CRIT(( "invariant violation: new target programdata too small" ));
     843           0 :   }
     844             : 
     845             :   /* Agave calls directly_invoke_loader_v3_deploy to deploy the new
     846             :      program to the program cache. We don't do that, but instead we
     847             :      perform the same checks as directly_invoke_loader_v3_deploy
     848             :      without modifying the program cache. We need to do the checks
     849             :      at this point so that we can fail the upgrade if the ELF is
     850             :      invalid.
     851             : 
     852             :      This is safe because the bpf migration code runs at the epoch
     853             :      boundary when the migration feature activates, before transaction
     854             :      execution.  The feature activation selects a new program-cache
     855             :      revision, so no explicit cache update is needed here.
     856             : 
     857             :      https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L437-L443*/
     858           0 :   uchar const * elf    = (uchar const *)new_target_program_data->data + PROGRAMDATA_METADATA_SIZE;
     859           0 :   ulong         elf_sz = new_target_program_data->data_sz - PROGRAMDATA_METADATA_SIZE;
     860           0 :   if( FD_UNLIKELY( fd_directly_invoke_loader_v3_deploy_checks( bank, runtime_stack, elf, elf_sz ) ) ) return;
     861             : 
     862             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L451-L459 */
     863           0 :   ulong lamports_to_burn;
     864           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->lamports, source->lamports, &lamports_to_burn ) ) ) return;
     865           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) )       return;
     866             : 
     867           0 :   ulong lamports_to_fund;
     868           0 :   if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->lamports, new_target_program_data->lamports, &lamports_to_fund ) ) ) return;
     869             : 
     870             :   /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L462-L468 */
     871           0 :   tmp_account_store( bank, accdb, new_target_program,      capture_ctx, 0 );
     872           0 :   tmp_account_store( bank, accdb, new_target_program_data, capture_ctx, 1 );
     873             : 
     874           0 :   fd_tmp_account_t * empty = &runtime_stack->bpf_migration->empty;
     875           0 :   tmp_account_new( empty, 0UL );
     876           0 :   empty->pubkey = source->pubkey;
     877           0 :   tmp_account_store( bank, accdb, empty, capture_ctx, 0 );
     878             : 
     879             :   /* NB: Agave updates "delta_off_chain", using these two fields,
     880             :      which is not consensus-critical (only used for Agave stats)
     881             :      so we don't update this in our migration code or store this in
     882             :      our bank. */
     883           0 :   (void)old_data_sz;
     884           0 :   (void)new_data_sz;
     885             : 
     886           0 :   fd_memset( runtime_stack->bpf_migration, 0, sizeof(fd_runtime_stack_bpf_migration_t) );
     887           0 : }

Generated by: LCOV version 1.14