Line data Source code
1 : #include "fd_prog_load.h" 2 : #include "../runtime/program/fd_bpf_loader_program.h" 3 : #include "../runtime/program/fd_loader_v4_program.h" 4 : #include "../runtime/sysvar/fd_sysvar_epoch_schedule.h" 5 : #include "../runtime/fd_system_ids.h" 6 : 7 : static fd_prog_info_t * 8 : fd_prog_info_v4( fd_prog_info_t * out, 9 0 : fd_accdb_ro_t const * ro ) { 10 : 11 0 : ulong data_sz = fd_accdb_ref_data_sz( ro ); 12 0 : if( FD_UNLIKELY( data_sz<LOADER_V4_PROGRAM_DATA_OFFSET ) ) { 13 0 : FD_LOG_WARNING(( "program data account is invalid" )); 14 0 : return NULL; 15 0 : } 16 : 17 0 : fd_loader_v4_state_t state = FD_LOAD( fd_loader_v4_state_t, fd_accdb_ref_data_const( ro ) ); 18 0 : if( FD_UNLIKELY( state.status==FD_LOADER_V4_STATUS_ENUM_RETRACTED ) ) { 19 0 : FD_LOG_WARNING(( "program data account is not executable" )); 20 0 : return NULL; 21 0 : } 22 : 23 0 : *out = (fd_prog_info_t) { 24 0 : .elf_off = LOADER_V4_PROGRAM_DATA_OFFSET, 25 0 : .elf_sz = data_sz - LOADER_V4_PROGRAM_DATA_OFFSET, 26 0 : .deploy_slot = state.slot 27 0 : }; 28 0 : return out; 29 0 : } 30 : 31 : static fd_prog_info_t * 32 : fd_prog_info_v3( fd_prog_info_t * out, 33 18 : fd_accdb_ro_t const * ro ) { 34 : 35 18 : ulong data_sz = fd_accdb_ref_data_sz( ro ); 36 18 : fd_bincode_decode_ctx_t decode = fd_bincode_decode_ctx( fd_accdb_ref_data_const( ro ), data_sz ); 37 18 : ulong total_sz = 0UL; 38 18 : if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_decode_footprint( &decode, &total_sz )!=FD_BINCODE_SUCCESS ) ) { 39 3 : FD_LOG_WARNING(( "program data account is invalid" )); 40 3 : return NULL; 41 3 : } 42 15 : if( FD_UNLIKELY( fd_accdb_ref_data_sz( ro )<PROGRAMDATA_METADATA_SIZE ) ) { 43 3 : FD_LOG_WARNING(( "program data account is too small" )); 44 3 : return NULL; 45 3 : } 46 12 : fd_bpf_upgradeable_loader_state_t state; 47 12 : fd_bpf_upgradeable_loader_state_decode( &state, &decode ); 48 12 : if( FD_UNLIKELY( state.discriminant!=fd_bpf_upgradeable_loader_state_enum_program_data ) ) { 49 3 : FD_LOG_WARNING(( "loader v3 account is not a program data account" )); 50 3 : return NULL; 51 3 : } 52 : 53 9 : *out = (fd_prog_info_t) { 54 9 : .elf_off = PROGRAMDATA_METADATA_SIZE, 55 9 : .elf_sz = data_sz - PROGRAMDATA_METADATA_SIZE, 56 9 : .deploy_slot = state.inner.program_data.slot 57 9 : }; 58 9 : return out; 59 12 : } 60 : 61 : static fd_prog_info_t * 62 : fd_prog_info_v1( fd_prog_info_t * out, 63 75 : fd_accdb_ro_t const * ro ) { 64 75 : *out = (fd_prog_info_t) { 65 75 : .elf_off = 0UL, 66 75 : .elf_sz = fd_accdb_ref_data_sz( ro ), 67 75 : .deploy_slot = 0UL 68 75 : }; 69 75 : return out; 70 75 : } 71 : 72 : /* We determine the BPF loader type based off of the program acount owner, 73 : instead of the programdata owner. 74 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.5/svm/src/program_loader.rs#L29 */ 75 : fd_prog_info_t * 76 : fd_prog_info( fd_prog_info_t * out, 77 : fd_accdb_ro_t * ro, 78 96 : fd_pubkey_t const * program_owner ){ 79 96 : if( fd_pubkey_eq( program_owner, &fd_solana_bpf_loader_upgradeable_program_id ) ) { 80 18 : return fd_prog_info_v3( out, ro ); 81 78 : } else if( fd_pubkey_eq( program_owner, &fd_solana_bpf_loader_v4_program_id ) ) { 82 0 : return fd_prog_info_v4( out, ro ); 83 78 : } else if( fd_pubkey_eq( program_owner, &fd_solana_bpf_loader_program_id ) || 84 78 : fd_pubkey_eq( program_owner, &fd_solana_bpf_loader_deprecated_program_id ) ) { 85 75 : return fd_prog_info_v1( out, ro ); 86 75 : } else { 87 3 : FD_BASE58_ENCODE_32_BYTES( fd_accdb_ref_address( ro ), addr_b58 ); 88 3 : FD_BASE58_ENCODE_32_BYTES( program_owner->key, owner_b58 ); 89 3 : FD_LOG_WARNING(( "unsupported program data account (address=%s program_owner=%s)", addr_b58, owner_b58 )); 90 3 : return NULL; 91 3 : } 92 96 : } 93 : 94 : FD_FN_PURE fd_prog_versions_t 95 : fd_prog_versions( fd_features_t const * features, 96 81 : ulong slot ) { 97 81 : int disable_v0 = FD_FEATURE_ACTIVE( slot, features, disable_sbpf_v0_execution ); 98 81 : int reenable_v0 = FD_FEATURE_ACTIVE( slot, features, reenable_sbpf_v0_execution ); 99 81 : int enable_v0 = !disable_v0 || reenable_v0; 100 81 : int enable_v1 = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v1_deployment_and_execution ); 101 81 : int enable_v2 = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v2_deployment_and_execution ); 102 : 103 81 : fd_prog_versions_t v = {0}; 104 81 : if( enable_v2 ) { 105 75 : v.max_sbpf_version = FD_SBPF_V2; 106 75 : } else if( enable_v1 ) { 107 0 : v.max_sbpf_version = FD_SBPF_V1; 108 6 : } else { 109 6 : v.max_sbpf_version = FD_SBPF_V0; 110 6 : } 111 81 : v.min_sbpf_version = enable_v0 ? FD_SBPF_V0 : fd_uint_min( FD_SBPF_V2, v.max_sbpf_version ); 112 81 : return v; 113 81 : } 114 : 115 : fd_prog_load_env_t * 116 : fd_prog_load_env_from_bank( fd_prog_load_env_t * env, 117 6 : fd_bank_t const * bank ) { 118 6 : *env = (fd_prog_load_env_t) { 119 6 : .features = &bank->f.features, 120 6 : .epoch = bank->f.epoch, 121 6 : .epoch_slot0 = fd_epoch_slot0( &bank->f.epoch_schedule, bank->f.epoch ) 122 6 : }; 123 6 : return env; 124 6 : }