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