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

Generated by: LCOV version 1.14