LCOV - code coverage report
Current view: top level - flamenco/runtime - fd_core_bpf_migration.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 289 0.0 %
Date: 2025-10-27 04:40:00 Functions: 0 10 0.0 %

          Line data    Source code
       1             : #include "sysvar/fd_sysvar_rent.h"
       2             : #include "program/fd_bpf_loader_program.h"
       3             : #include "program/fd_builtin_programs.h"
       4             : #include "fd_runtime_stack.h"
       5             : #include "fd_pubkey_utils.h"
       6             : #include "fd_system_ids.h"
       7             : #include <assert.h>
       8             : 
       9             : static fd_pubkey_t
      10           0 : get_program_data_address( fd_pubkey_t const * program_addr ) {
      11           0 :   uchar const * seed    = program_addr->uc;
      12           0 :   ulong         seed_sz = 32UL;
      13           0 :   fd_pubkey_t   out;
      14           0 :   uint          custom_err;
      15           0 :   uchar         out_bump_seed;
      16           0 :   fd_pubkey_find_program_address( &fd_solana_bpf_loader_upgradeable_program_id, 1UL, &seed, &seed_sz, &out, &out_bump_seed, &custom_err );
      17           0 :   return out;
      18           0 : }
      19             : 
      20             : fd_tmp_account_t *
      21             : tmp_account_new( fd_tmp_account_t * acc,
      22           0 :                  ulong              acc_sz ) {
      23           0 :   acc->data_sz = acc_sz;
      24           0 :   fd_memset( acc->data, 0, acc_sz );
      25           0 :   return acc;
      26           0 : }
      27             : 
      28             : fd_tmp_account_t *
      29             : tmp_account_read( fd_tmp_account_t *        acc,
      30             :                   fd_funk_t *               funk,
      31             :                   fd_funk_txn_xid_t const * xid,
      32           0 :                   fd_pubkey_t const *       addr ) {
      33           0 :   int opt_err = 0;
      34           0 :   fd_account_meta_t const * meta = fd_funk_get_acc_meta_readonly(
      35           0 :       funk,
      36           0 :       xid,
      37           0 :       addr,
      38           0 :       NULL,
      39           0 :       &opt_err,
      40           0 :       NULL );
      41           0 :   if( FD_UNLIKELY( opt_err!=FD_ACC_MGR_SUCCESS ) ) {
      42           0 :     if( FD_LIKELY( opt_err==FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) ) return NULL;
      43           0 :     FD_LOG_CRIT(( "fd_funk_get_acc_meta_readonly failed (%d) %s", opt_err, FD_BASE58_ENC_32_ALLOCA( addr ) ));
      44           0 :   }
      45           0 :   tmp_account_new( acc, meta->dlen );
      46           0 :   acc->meta = *meta;
      47           0 :   acc->addr = *addr;
      48           0 :   fd_memcpy( acc->data, fd_account_meta_get_data_const( meta ), meta->dlen );
      49           0 :   acc->data_sz = meta->dlen;
      50           0 :   return acc;
      51           0 : }
      52             : 
      53             : void
      54             : tmp_account_store( fd_tmp_account_t *        acc,
      55             :                    fd_accdb_user_t *         accdb,
      56             :                    fd_funk_txn_xid_t const * xid,
      57             :                    fd_bank_t *               bank,
      58           0 :                    fd_capture_ctx_t *        capture_ctx ) {
      59           0 :   if( FD_UNLIKELY( fd_pubkey_eq( &acc->addr, &fd_solana_system_program_id ) ) ) {
      60           0 :     FD_LOG_ERR(( "Attempted to write to the system program account" ));
      61           0 :   }
      62             : 
      63             :   /* FIXME usage of "txn_account" */
      64           0 :   fd_txn_account_t rec[1];
      65           0 :   fd_funk_rec_prepare_t prepare = {0};
      66           0 :   int ok = !!fd_txn_account_init_from_funk_mutable(
      67           0 :       rec,
      68           0 :       &acc->addr,
      69           0 :       accdb,
      70           0 :       xid,
      71           0 :       1,
      72           0 :       acc->data_sz,
      73           0 :       &prepare );
      74           0 :   if( FD_UNLIKELY( !ok ) ) {
      75           0 :     FD_LOG_CRIT(( "fd_txn_account_init_from_funk_mutable failed" ));
      76           0 :   }
      77             : 
      78           0 :   fd_lthash_value_t prev_hash[1];
      79           0 :   fd_hashes_account_lthash( &acc->addr, fd_txn_account_get_meta( rec ), fd_txn_account_get_data( rec ), prev_hash );
      80             : 
      81           0 :   fd_txn_account_set_executable( rec, acc->meta.executable    );
      82           0 :   fd_txn_account_set_owner     ( rec, fd_type_pun_const( acc->meta.owner ) );
      83           0 :   fd_txn_account_set_lamports  ( rec, acc->meta.lamports      );
      84           0 :   fd_txn_account_set_data      ( rec, acc->data, acc->data_sz );
      85             : 
      86           0 :   fd_hashes_update_lthash( rec, prev_hash, bank, capture_ctx );
      87           0 :   fd_txn_account_mutable_fini( rec, accdb, &prepare );
      88           0 : }
      89             : 
      90             : /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_core_bpf.rs#L12 */
      91             : 
      92             : struct target_core_bpf {
      93             :   fd_pubkey_t        program_address;
      94             :   fd_tmp_account_t * program_data_account;
      95             :   fd_pubkey_t        upgrade_authority_address;
      96             :   uint               has_upgrade_authority_address : 1;
      97             : };
      98             : 
      99             : typedef struct target_core_bpf target_core_bpf_t;
     100             : 
     101             : /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L13 */
     102             : 
     103             : struct target_builtin {
     104             :   fd_tmp_account_t * program_account;
     105             :   fd_pubkey_t        program_data_address;
     106             : };
     107             : 
     108             : typedef struct target_builtin target_builtin_t;
     109             : 
     110             : /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L22 */
     111             : 
     112             : target_builtin_t *
     113             : target_builtin_new_checked( target_builtin_t *        target_builtin,
     114             :                             fd_pubkey_t const *       program_address,
     115             :                             int                       migration_target,
     116             :                             fd_funk_t *               funk,
     117             :                             fd_funk_txn_xid_t const * xid,
     118           0 :                             fd_runtime_stack_t *      runtime_stack ) {
     119             : 
     120             :   /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L27-L49 */
     121             : 
     122           0 :   fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
     123           0 :   switch( migration_target ) {
     124           0 :   case FD_CORE_BPF_MIGRATION_TARGET_BUILTIN:
     125           0 :     if( FD_UNLIKELY( !tmp_account_read( program_account, funk, xid, program_address ) ) ) {
     126             :       /* CoreBpfMigrationError::AccountNotFound(*program_address) */
     127           0 :       return NULL;
     128           0 :     }
     129           0 :     if( FD_UNLIKELY( 0!=memcmp( program_account->meta.owner, &fd_solana_native_loader_id, 32 ) ) ) {
     130             :       /* CoreBpfMigrationError::IncorrectOwner(*program_address) */
     131           0 :       return NULL;
     132           0 :     }
     133           0 :     break;
     134           0 :   case FD_CORE_BPF_MIGRATION_TARGET_STATELESS: {
     135             :     /* Program account should not exist */
     136           0 :     int opt_err = 0;
     137           0 :     fd_funk_get_acc_meta_readonly(
     138           0 :         funk,
     139           0 :         xid,
     140           0 :         program_address,
     141           0 :         NULL,
     142           0 :         &opt_err,
     143           0 :         NULL );
     144           0 :     if( opt_err==FD_ACC_MGR_SUCCESS ) {
     145             :       /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
     146           0 :       return NULL;
     147           0 :     } else if( opt_err!=FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) {
     148           0 :       FD_LOG_ERR(( "database error: %d", opt_err ));
     149           0 :     }
     150           0 :     break;
     151           0 :   }
     152           0 :   default:
     153           0 :     FD_LOG_ERR(( "invalid migration_target %d", migration_target ));
     154           0 :   }
     155             : 
     156             :   /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L51 */
     157             : 
     158           0 :   fd_pubkey_t program_data_address = get_program_data_address( program_address );
     159             : 
     160             :   /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L53-L61 */
     161             : 
     162           0 :   do {
     163             :     /* Program data account should not exist */
     164           0 :     int opt_err = 0;
     165           0 :     fd_funk_get_acc_meta_readonly(
     166           0 :         funk,
     167           0 :         xid,
     168           0 :         &program_data_address,
     169           0 :         NULL,
     170           0 :         &opt_err,
     171           0 :         NULL );
     172           0 :     if( opt_err==FD_ACC_MGR_SUCCESS ) {
     173             :       /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
     174           0 :       return NULL;
     175           0 :     } else if( opt_err!=FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) {
     176           0 :       FD_LOG_ERR(( "database error: %d", opt_err ));
     177           0 :     }
     178           0 :   } while(0);
     179             : 
     180             :   /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L63-L67 */
     181             : 
     182           0 :   *target_builtin = (target_builtin_t) {
     183           0 :     .program_account      = program_account,
     184           0 :     .program_data_address = program_data_address
     185           0 :   };
     186           0 :   return target_builtin;
     187           0 : }
     188             : 
     189             : /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L22-L49 */
     190             : 
     191             : static fd_tmp_account_t *
     192             : source_buffer_new_checked( fd_tmp_account_t *        acc,
     193             :                            fd_funk_t *               funk,
     194             :                            fd_funk_txn_xid_t const * xid,
     195           0 :                            fd_pubkey_t const *       pubkey ) {
     196             : 
     197           0 :   if( FD_UNLIKELY( !tmp_account_read( acc, funk, xid, pubkey ) ) ) {
     198             :     /* CoreBpfMigrationError::AccountNotFound(*buffer_address) */
     199           0 :     return NULL;
     200           0 :   }
     201             : 
     202           0 :   if( FD_UNLIKELY( 0!=memcmp( acc->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, 32 ) ) ) {
     203             :     /* CoreBpfMigrationError::IncorrectOwner(*buffer_address) */
     204           0 :     return NULL;
     205           0 :   }
     206             : 
     207           0 :   ulong const buffer_metadata_sz = 37UL;
     208           0 :   if( acc->data_sz < buffer_metadata_sz ) {
     209             :     /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
     210           0 :     return NULL;
     211           0 :   }
     212             : 
     213           0 :   fd_bpf_upgradeable_loader_state_t state[1];
     214           0 :   if( FD_UNLIKELY( !fd_bincode_decode_static(
     215           0 :       bpf_upgradeable_loader_state, state,
     216           0 :       acc->data, acc->data_sz,
     217           0 :       NULL ) ) ) {
     218           0 :     return NULL;
     219           0 :   }
     220             : 
     221           0 :   return acc;
     222           0 : }
     223             : 
     224             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L82-L95 */
     225             : 
     226             : static fd_tmp_account_t *
     227             : new_target_program_account( fd_tmp_account_t *        acc,
     228             :                             target_builtin_t const *  target,
     229           0 :                             fd_rent_t const *         rent ) {
     230             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L86-L88 */
     231           0 :   fd_bpf_upgradeable_loader_state_t state = {
     232           0 :     .discriminant = fd_bpf_upgradeable_loader_state_enum_program,
     233           0 :     .inner = {
     234           0 :       .program = {
     235           0 :         .programdata_address = target->program_data_address,
     236           0 :       }
     237           0 :     }
     238           0 :   };
     239             : 
     240           0 :   tmp_account_new( acc, fd_bpf_upgradeable_loader_state_size( &state ) );
     241           0 :   acc->meta.lamports   = fd_rent_exempt_minimum_balance( rent, SIZE_OF_PROGRAM );
     242           0 :   acc->meta.executable = 1;
     243           0 :   memcpy( acc->meta.owner, fd_solana_bpf_loader_upgradeable_program_id.uc, sizeof(fd_pubkey_t) );
     244             : 
     245           0 :   return acc;
     246           0 : }
     247             : 
     248             : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L108-L153 */
     249             : static fd_tmp_account_t *
     250             : new_target_program_data_account( fd_tmp_account_t *       acc,
     251             :                                  fd_tmp_account_t const * source,
     252             :                                  fd_pubkey_t const *      upgrade_authority_address,
     253             :                                  fd_rent_t const *        rent,
     254           0 :                                  ulong                    slot ) {
     255           0 :   ulong const buffer_metadata_sz = BUFFER_METADATA_SIZE;
     256             : 
     257           0 :   if( FD_UNLIKELY( source->data_sz < buffer_metadata_sz ) )
     258           0 :     return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
     259             : 
     260           0 :   fd_bpf_upgradeable_loader_state_t state;
     261           0 :   if( !fd_bincode_decode_static(
     262           0 :       bpf_upgradeable_loader_state,
     263           0 :       &state,
     264           0 :       source->data,
     265           0 :       buffer_metadata_sz,
     266           0 :       NULL ) )
     267           0 :     return NULL;
     268             : 
     269           0 :   if( FD_UNLIKELY( state.discriminant!=fd_bpf_upgradeable_loader_state_enum_buffer ) )
     270           0 :     return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
     271             : 
     272           0 :   if( FD_UNLIKELY( state.inner.buffer.has_authority_address != (!!upgrade_authority_address) ) )
     273           0 :     return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
     274             : 
     275           0 :   if( FD_UNLIKELY( upgrade_authority_address &&
     276           0 :                    !fd_pubkey_eq( upgrade_authority_address, &state.inner.buffer.authority_address ) ) )
     277           0 :     return NULL; /* CoreBpfMigrationError::UpgradeAuthorityMismatch */
     278             : 
     279           0 :   void const * elf      = (uchar const *)source->data    + buffer_metadata_sz;
     280           0 :   ulong        elf_sz   = /*           */source->data_sz - buffer_metadata_sz;
     281             : 
     282           0 :   ulong        space    = PROGRAMDATA_METADATA_SIZE + elf_sz;
     283           0 :   ulong        lamports = fd_rent_exempt_minimum_balance( rent, space );
     284           0 :   fd_pubkey_t  owner    = fd_solana_bpf_loader_upgradeable_program_id;
     285             : 
     286           0 :   fd_bpf_upgradeable_loader_state_t programdata_meta = {
     287           0 :     .discriminant = fd_bpf_upgradeable_loader_state_enum_program_data,
     288           0 :     .inner = {
     289           0 :       .program_data = {
     290           0 :         .slot = slot,
     291           0 :         .has_upgrade_authority_address = !!upgrade_authority_address,
     292           0 :         .upgrade_authority_address     = upgrade_authority_address ? *upgrade_authority_address : (fd_pubkey_t){{0}}
     293           0 :       }
     294           0 :     }
     295           0 :   };
     296             : 
     297           0 :   tmp_account_new( acc, space );
     298           0 :   acc->meta.lamports = lamports;
     299           0 :   memcpy( acc->meta.owner, owner.uc, sizeof(fd_pubkey_t) );
     300           0 :   fd_bincode_encode_ctx_t ctx = { .data=acc->data, .dataend=(uchar *)acc->data+PROGRAMDATA_METADATA_SIZE };
     301           0 :   if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_encode( &programdata_meta, &ctx )!=FD_BINCODE_SUCCESS ) ) {
     302           0 :     FD_LOG_ERR(( "fd_bpf_upgradeable_loader_state_encode failed" ));
     303           0 :   }
     304           0 :   fd_memcpy( (uchar *)acc->data+PROGRAMDATA_METADATA_SIZE, elf, elf_sz );
     305             : 
     306           0 :   return acc;
     307           0 : }
     308             : 
     309             : void
     310             : migrate_builtin_to_core_bpf1( fd_core_bpf_migration_config_t const * config,
     311             :                               fd_accdb_user_t *                      accdb,
     312             :                               fd_funk_txn_xid_t const *              xid,
     313             :                               fd_bank_t *                            bank,
     314             :                               fd_runtime_stack_t *                   runtime_stack,
     315             :                               fd_pubkey_t const *                    builtin_program_id,
     316           0 :                               fd_capture_ctx_t *                     capture_ctx ) {
     317             : 
     318           0 :   target_builtin_t target[1];
     319           0 :   if( FD_UNLIKELY( !target_builtin_new_checked(
     320           0 :       target,
     321           0 :       builtin_program_id,
     322           0 :       config->migration_target,
     323           0 :       accdb->funk,
     324           0 :       xid,
     325           0 :       runtime_stack ) ) )
     326           0 :     return;
     327             : 
     328           0 :   fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
     329           0 :   if( FD_UNLIKELY( !source_buffer_new_checked(
     330           0 :       source,
     331           0 :       accdb->funk,
     332           0 :       xid,
     333           0 :       config->source_buffer_address ) ) )
     334           0 :     return;
     335             : 
     336           0 :   fd_rent_t const * rent = fd_bank_rent_query( bank );
     337           0 :   ulong const       slot = fd_bank_slot_get  ( bank );
     338             : 
     339           0 :   fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration.new_target_program;
     340           0 :   if( FD_UNLIKELY( !new_target_program_account(
     341           0 :       new_target_program,
     342           0 :       target,
     343           0 :       rent ) ) )
     344           0 :     return;
     345             : 
     346           0 :   fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
     347           0 :   if( FD_UNLIKELY( !new_target_program_data_account(
     348           0 :       new_target_program_data,
     349           0 :       source,
     350           0 :       config->upgrade_authority_address,
     351           0 :       rent,
     352           0 :       slot ) ) )
     353           0 :     return;
     354             : 
     355           0 :   ulong old_data_sz;
     356           0 :   if( FD_UNLIKELY( __builtin_uaddl_overflow(
     357           0 :       target->program_account->data_sz,
     358           0 :       source->data_sz,
     359           0 :       &old_data_sz ) ) ) {
     360           0 :     return;
     361           0 :   }
     362           0 :   ulong new_data_sz;
     363           0 :   if( FD_UNLIKELY( __builtin_uaddl_overflow(
     364           0 :       new_target_program     ->data_sz,
     365           0 :       new_target_program_data->data_sz,
     366           0 :       &new_data_sz ) ) ) {
     367           0 :     return;
     368           0 :   }
     369             : 
     370           0 :   assert( new_target_program_data->data_sz>=PROGRAMDATA_METADATA_SIZE );
     371           0 :   if( FD_UNLIKELY( !fd_directly_invoke_loader_v3_deploy(
     372           0 :       bank,
     373           0 :       accdb->funk->shmem,
     374           0 :       xid,
     375           0 :       &target->program_account->addr,
     376           0 :       new_target_program_data->data   +PROGRAMDATA_METADATA_SIZE,
     377           0 :       new_target_program_data->data_sz-PROGRAMDATA_METADATA_SIZE ) ) ) {
     378           0 :     return;
     379           0 :   }
     380             : 
     381           0 :   ulong lamports_to_burn;
     382           0 :   if( FD_UNLIKELY( __builtin_uaddl_overflow(
     383           0 :       target->program_account->meta.lamports,
     384           0 :       source->meta.lamports,
     385           0 :       &lamports_to_burn ) ) ) {
     386           0 :     return;
     387           0 :   }
     388           0 :   ulong lamports_to_fund;
     389           0 :   if( FD_UNLIKELY( __builtin_uaddl_overflow(
     390           0 :       new_target_program     ->meta.lamports,
     391           0 :       new_target_program_data->meta.lamports,
     392           0 :       &lamports_to_fund ) ) ) {
     393           0 :     return;
     394           0 :   }
     395             : 
     396             :   /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L286-L297 */
     397           0 :   ulong capitalization = fd_bank_capitalization_get( bank );
     398           0 :   int cap_ok = 1;
     399           0 :   if( lamports_to_burn>lamports_to_fund ) {
     400           0 :     cap_ok = __builtin_usubl_overflow(
     401           0 :         capitalization,
     402           0 :         (lamports_to_burn-lamports_to_fund),
     403           0 :         &capitalization );
     404           0 :   } else if( lamports_to_burn<lamports_to_fund ) {
     405           0 :     cap_ok = __builtin_uaddl_overflow(
     406           0 :         capitalization,
     407           0 :         (lamports_to_fund-lamports_to_burn),
     408           0 :         &capitalization );
     409           0 :   }
     410           0 :   if( FD_UNLIKELY( !cap_ok ) ) {
     411           0 :     FD_LOG_ERR(( "Capitalization overflow while migrating builtin program to core BPF" ));
     412           0 :   }
     413           0 :   fd_bank_capitalization_set( bank, capitalization );
     414             : 
     415             :   /* Write back accounts */
     416           0 :   tmp_account_store( new_target_program,      accdb, xid, bank, capture_ctx );
     417           0 :   tmp_account_store( new_target_program_data, accdb, xid, bank, capture_ctx );
     418           0 :   fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
     419           0 :   tmp_account_new( empty, 0UL );
     420           0 :   empty->addr = source->addr;
     421           0 :   tmp_account_store( empty, accdb, xid, bank, capture_ctx );
     422             : 
     423             :   /* FIXME "remove the built-in program from the bank's list of builtins" */
     424             :   /* FIXME "update account data size delta" */
     425           0 : }
     426             : 
     427             : /* Mimics migrate_builtin_to_core_bpf().
     428             :    https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L235-L318 */
     429             : void
     430             : fd_migrate_builtin_to_core_bpf( fd_bank_t *                            bank,
     431             :                                 fd_accdb_user_t *                      accdb,
     432             :                                 fd_funk_txn_xid_t const *              xid,
     433             :                                 fd_runtime_stack_t *                   runtime_stack,
     434             :                                 fd_core_bpf_migration_config_t const * config,
     435           0 :                                 fd_capture_ctx_t *                     capture_ctx ) {
     436           0 :   migrate_builtin_to_core_bpf1( config, accdb, xid, bank, runtime_stack, config->builtin_program_id, capture_ctx );
     437           0 : }

Generated by: LCOV version 1.14