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

Generated by: LCOV version 1.14