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 :
6 : /* Similar to the below function, but gets the executable program content for the v4 loader.
7 : Unlike the v3 loader, the programdata is stored in a single program account. The program must
8 : NOT be retracted to be added to the cache. Returns a pointer to the programdata on success,
9 : and NULL on failure.
10 :
11 : Reasons for failure include:
12 : - The program state cannot be read from the account data or is in the `retracted` state. */
13 : static uchar const *
14 : fd_get_executable_program_content_for_v4_loader( fd_txn_account_t const * program_acc,
15 0 : ulong * program_data_len ) {
16 0 : int err;
17 :
18 : /* Get the current loader v4 state. This implicitly also checks the dlen. */
19 0 : fd_loader_v4_state_t const * state = fd_loader_v4_get_state( program_acc, &err );
20 0 : if( FD_UNLIKELY( err ) ) {
21 0 : return NULL;
22 0 : }
23 :
24 : /* The program must be deployed or finalized. */
25 0 : if( FD_UNLIKELY( fd_loader_v4_status_is_retracted( state ) ) ) {
26 0 : return NULL;
27 0 : }
28 :
29 : /* This subtraction is safe because get_state() implicitly checks the
30 : dlen. */
31 0 : *program_data_len = fd_txn_account_get_data_len( program_acc )-LOADER_V4_PROGRAM_DATA_OFFSET;
32 0 : return fd_txn_account_get_data( program_acc )+LOADER_V4_PROGRAM_DATA_OFFSET;
33 0 : }
34 :
35 : /* Gets the programdata for a v3 loader-owned account by decoding the account data
36 : as well as the programdata account. Returns a pointer to the programdata on success,
37 : and NULL on failure.
38 :
39 : Reasons for failure include:
40 : - The program account data cannot be decoded or is not in the `program` state.
41 : - The programdata account is not large enough to hold at least `PROGRAMDATA_METADATA_SIZE` bytes. */
42 : static uchar const *
43 : fd_get_executable_program_content_for_upgradeable_loader( fd_funk_t const * funk,
44 : fd_funk_txn_xid_t const * xid,
45 : fd_txn_account_t const * program_acc,
46 : ulong * program_data_len,
47 0 : fd_funk_txn_xid_t * out_xid ) {
48 0 : fd_bpf_upgradeable_loader_state_t program_account_state[1];
49 0 : if( FD_UNLIKELY( !fd_bincode_decode_static(
50 0 : bpf_upgradeable_loader_state,
51 0 : program_account_state,
52 0 : fd_txn_account_get_data( program_acc ),
53 0 : fd_txn_account_get_data_len( program_acc ),
54 0 : NULL ) ) ) {
55 0 : return NULL;
56 0 : }
57 0 : if( !fd_bpf_upgradeable_loader_state_is_program( program_account_state ) ) {
58 0 : return NULL;
59 0 : }
60 :
61 0 : fd_pubkey_t * programdata_address = &program_account_state->inner.program.programdata_address;
62 :
63 0 : fd_account_meta_t const * meta = fd_funk_get_acc_meta_readonly(
64 0 : funk, xid, programdata_address, NULL, NULL, out_xid );
65 0 : if( FD_UNLIKELY( !meta ) ) return NULL;
66 0 : fd_txn_account_t _rec[1];
67 0 : fd_txn_account_t * programdata_acc = fd_txn_account_join( fd_txn_account_new( _rec, programdata_address, (void *)meta, 0 ), funk->wksp );
68 0 : if( FD_UNLIKELY( !programdata_acc ) ) FD_LOG_CRIT(( "fd_txn_account_new failed" ));
69 :
70 : /* We don't actually need to decode here, just make sure that the account
71 : can be decoded successfully. */
72 0 : fd_bincode_decode_ctx_t ctx_programdata = {
73 0 : .data = fd_txn_account_get_data( programdata_acc ),
74 0 : .dataend = fd_txn_account_get_data( programdata_acc ) + fd_txn_account_get_data_len( programdata_acc ),
75 0 : };
76 :
77 0 : ulong total_sz = 0UL;
78 0 : if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_decode_footprint( &ctx_programdata, &total_sz ) ) ) {
79 0 : return NULL;
80 0 : }
81 :
82 0 : if( FD_UNLIKELY( fd_txn_account_get_data_len( programdata_acc )<PROGRAMDATA_METADATA_SIZE ) ) {
83 0 : return NULL;
84 0 : }
85 :
86 0 : *program_data_len = fd_txn_account_get_data_len( programdata_acc ) - PROGRAMDATA_METADATA_SIZE;
87 0 : return fd_txn_account_get_data( programdata_acc ) + PROGRAMDATA_METADATA_SIZE;
88 0 : }
89 :
90 : /* Gets the programdata for a v1/v2 loader-owned account by returning a
91 : pointer to the account data. Returns a pointer to the programdata on
92 : success. Given the txn account API always returns a handle to the
93 : account data, this function should NEVER return NULL (since the
94 : programdata of v1 and v2 loader) accounts start at the beginning of
95 : the data. */
96 : static uchar const *
97 : fd_get_executable_program_content_for_v1_v2_loaders( fd_txn_account_t const * program_acc,
98 39 : ulong * program_data_len ) {
99 39 : *program_data_len = fd_txn_account_get_data_len( program_acc );
100 39 : return fd_txn_account_get_data( program_acc );
101 39 : }
102 :
103 : uchar const *
104 : fd_prog_load_elf( fd_funk_t const * accdb,
105 : fd_funk_txn_xid_t const * xid,
106 : void const * _prog_addr,
107 : ulong * out_sz,
108 45 : fd_funk_txn_xid_t * out_xid ) {
109 45 : fd_pubkey_t prog_addr = FD_LOAD( fd_pubkey_t, _prog_addr );
110 :
111 45 : fd_funk_txn_xid_t _out_xid;
112 45 : if( !out_xid ) out_xid = &_out_xid;
113 45 : fd_account_meta_t const * meta = fd_funk_get_acc_meta_readonly(
114 45 : accdb, xid, &prog_addr, NULL, NULL, out_xid );
115 45 : if( FD_UNLIKELY( !meta ) ) return NULL;
116 42 : fd_txn_account_t _rec[1];
117 42 : fd_txn_account_t * rec = fd_txn_account_join( fd_txn_account_new( _rec, &prog_addr, (void *)meta, 0 ), accdb->wksp );
118 42 : if( FD_UNLIKELY( !rec ) ) FD_LOG_CRIT(( "fd_txn_account_new failed" ));
119 :
120 : /* v1/v2 loaders: Programdata is just the account data.
121 : v3 loader: Programdata lives in a separate account. Deserialize the
122 : program account and lookup the programdata account.
123 : Deserialize the programdata account.
124 : v4 loader: Programdata lives in the program account, offset by
125 : LOADER_V4_PROGRAM_DATA_OFFSET. */
126 42 : fd_pubkey_t const * owner = fd_txn_account_get_owner( rec );
127 42 : uchar const * elf = NULL;
128 42 : if( !memcmp( owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) {
129 : /* When a loader v3 program is redeployed, the programdata account
130 : is always updated. Therefore, use the programdata account's
131 : 'last update XID' instead of the program account's. */
132 0 : elf = fd_get_executable_program_content_for_upgradeable_loader( accdb, xid, rec, out_sz, out_xid );
133 42 : } else if( !memcmp( owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
134 0 : elf = fd_get_executable_program_content_for_v4_loader( rec, out_sz );
135 42 : } else if( !memcmp( owner, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) ||
136 42 : !memcmp( owner, fd_solana_bpf_loader_deprecated_program_id.key, sizeof(fd_pubkey_t) ) ) {
137 39 : elf = fd_get_executable_program_content_for_v1_v2_loaders( rec, out_sz );
138 39 : }
139 :
140 42 : if( FD_LIKELY( !elf ) ) {
141 3 : fd_funk_txn_xid_set_root( out_xid );
142 3 : }
143 :
144 42 : return elf;
145 42 : }
146 :
147 : FD_FN_PURE fd_prog_versions_t
148 : fd_prog_versions( fd_features_t const * features,
149 39 : ulong slot ) {
150 39 : int disable_v0 = FD_FEATURE_ACTIVE( slot, features, disable_sbpf_v0_execution );
151 39 : int reenable_v0 = FD_FEATURE_ACTIVE( slot, features, reenable_sbpf_v0_execution );
152 39 : int enable_v0 = !disable_v0 || reenable_v0;
153 39 : int enable_v1 = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v1_deployment_and_execution );
154 39 : int enable_v2 = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v2_deployment_and_execution );
155 39 : int enable_v3 = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v3_deployment_and_execution );
156 :
157 39 : fd_prog_versions_t v = {0};
158 39 : v.min_sbpf_version = enable_v0 ? FD_SBPF_V0 : FD_SBPF_V3;
159 39 : if( enable_v3 ) {
160 39 : v.max_sbpf_version = FD_SBPF_V3;
161 39 : } else if( enable_v2 ) {
162 0 : v.max_sbpf_version = FD_SBPF_V2;
163 0 : } else if( enable_v1 ) {
164 0 : v.max_sbpf_version = FD_SBPF_V1;
165 0 : } else {
166 0 : v.max_sbpf_version = FD_SBPF_V0;
167 0 : }
168 39 : return v;
169 39 : }
170 :
171 :
172 : fd_prog_load_env_t *
173 : fd_prog_load_env_from_bank( fd_prog_load_env_t * env,
174 0 : fd_bank_t const * bank ) {
175 0 : *env = (fd_prog_load_env_t) {
176 0 : .features = fd_bank_features_query( bank ),
177 0 : .slot = fd_bank_slot_get ( bank ),
178 0 : .epoch = fd_bank_epoch_get ( bank ),
179 0 : .epoch_slot0 = fd_epoch_slot0( fd_bank_epoch_schedule_query( bank ), fd_bank_epoch_get( bank ) )
180 0 : };
181 0 : return env;
182 0 : }
|