Line data Source code
1 : #include "fd_prog_load.h"
2 : #include "../accdb/fd_accdb_sync.h"
3 : #include "../runtime/program/fd_bpf_loader_program.h"
4 : #include "../runtime/program/fd_loader_v4_program.h"
5 : #include "../runtime/sysvar/fd_sysvar_epoch_schedule.h"
6 : #include "../runtime/fd_system_ids.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 564 : fd_get_executable_program_content_for_v4_loader( fd_accdb_ro_t const * ro ) {
17 564 : int err;
18 :
19 : /* Get the current loader v4 state. This implicitly also checks the dlen. */
20 564 : void const * data = fd_accdb_ref_data_const( ro );
21 564 : ulong data_sz = fd_accdb_ref_data_sz( ro );
22 564 : fd_loader_v4_state_t const * state = fd_loader_v4_get_state( data, data_sz, &err );
23 564 : if( FD_UNLIKELY( err ) ) {
24 0 : return NULL;
25 0 : }
26 :
27 : /* The program must be deployed or finalized. */
28 564 : if( FD_UNLIKELY( fd_loader_v4_status_is_retracted( state ) ) ) {
29 0 : return NULL;
30 0 : }
31 :
32 : /* This subtraction is safe because get_state() implicitly checks the
33 : dlen. */
34 564 : return (uchar const *)data+LOADER_V4_PROGRAM_DATA_OFFSET;
35 564 : }
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 fd_accdb_ro_t *
45 : fd_prog_load_v3( fd_accdb_user_t * accdb,
46 : fd_funk_txn_xid_t const * xid,
47 : fd_accdb_ro_t * progdata,
48 : fd_accdb_ro_t const * prog,
49 21 : ulong * out_offset ) {
50 21 : fd_bpf_upgradeable_loader_state_t program_account_state[1];
51 21 : if( FD_UNLIKELY( !fd_bincode_decode_static(
52 21 : bpf_upgradeable_loader_state,
53 21 : program_account_state,
54 21 : fd_accdb_ref_data_const( prog ),
55 21 : fd_accdb_ref_data_sz ( prog ) ) ) ) {
56 0 : return NULL;
57 0 : }
58 21 : if( !fd_bpf_upgradeable_loader_state_is_program( program_account_state ) ) {
59 0 : return NULL;
60 0 : }
61 :
62 21 : fd_pubkey_t * programdata_address = &program_account_state->inner.program.programdata_address;
63 :
64 21 : if( FD_UNLIKELY( !fd_accdb_open_ro( accdb, progdata, xid, programdata_address ) ) ) {
65 0 : return NULL;
66 0 : }
67 :
68 : /* We don't actually need to decode here, just make sure that the account
69 : can be decoded successfully. */
70 21 : fd_bincode_decode_ctx_t ctx_programdata = {
71 21 : .data = fd_accdb_ref_data_const( progdata ),
72 21 : .dataend = (uchar const *)fd_accdb_ref_data_const( progdata ) + fd_accdb_ref_data_sz( progdata ),
73 21 : };
74 :
75 21 : ulong total_sz = 0UL;
76 21 : if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_decode_footprint( &ctx_programdata, &total_sz ) ) ) {
77 0 : fd_accdb_close_ro( accdb, progdata );
78 0 : return NULL;
79 0 : }
80 :
81 21 : if( FD_UNLIKELY( fd_accdb_ref_data_sz( progdata )<PROGRAMDATA_METADATA_SIZE ) ) {
82 0 : fd_accdb_close_ro( accdb, progdata );
83 0 : return NULL;
84 0 : }
85 :
86 21 : *out_offset = PROGRAMDATA_METADATA_SIZE;
87 21 : return progdata;
88 21 : }
89 :
90 : fd_accdb_ro_t *
91 : fd_prog_load_elf( fd_accdb_user_t * accdb,
92 : fd_funk_txn_xid_t const * xid,
93 : fd_accdb_ro_t * out,
94 : void const * prog_addr,
95 1404 : ulong * out_offset ) {
96 1404 : fd_accdb_ro_t prog[1];
97 1404 : if( FD_UNLIKELY( !fd_accdb_open_ro( accdb, prog, xid, prog_addr ) ) ) {
98 0 : return NULL;
99 0 : }
100 :
101 : /* v1/v2 loaders: Programdata is just the account data.
102 : v3 loader: Programdata lives in a separate account. Deserialize the
103 : program account and lookup the programdata account.
104 : Deserialize the programdata account.
105 : v4 loader: Programdata lives in the program account, offset by
106 : LOADER_V4_PROGRAM_DATA_OFFSET. */
107 1404 : void const * owner = fd_accdb_ref_owner( prog );
108 1404 : if( !memcmp( owner, fd_solana_bpf_loader_upgradeable_program_id.key, sizeof(fd_pubkey_t) ) ) {
109 :
110 : /* When a loader v3 program is redeployed, the programdata account
111 : is always updated. Therefore, use the programdata account's
112 : 'last update XID' instead of the program account's. */
113 21 : fd_accdb_ro_t progdata_[1];
114 21 : fd_accdb_ro_t * progdata = fd_prog_load_v3( accdb, xid, progdata_, prog, out_offset );
115 21 : fd_accdb_close_ro( accdb, prog );
116 21 : if( !progdata ) return NULL;
117 21 : *out = *progdata;
118 :
119 1383 : } else if( !memcmp( owner, fd_solana_bpf_loader_v4_program_id.key, sizeof(fd_pubkey_t) ) ) {
120 :
121 564 : if( !fd_get_executable_program_content_for_v4_loader( prog ) ) {
122 0 : fd_accdb_close_ro( accdb, prog );
123 0 : return NULL;
124 0 : }
125 564 : *out = *prog;
126 564 : *out_offset = LOADER_V4_PROGRAM_DATA_OFFSET;
127 :
128 819 : } else if( !memcmp( owner, fd_solana_bpf_loader_program_id.key, sizeof(fd_pubkey_t) ) ||
129 819 : !memcmp( owner, fd_solana_bpf_loader_deprecated_program_id.key, sizeof(fd_pubkey_t) ) ) {
130 :
131 819 : *out = *prog;
132 819 : *out_offset = 0UL;
133 :
134 819 : } else {
135 0 : fd_accdb_close_ro( accdb, prog );
136 0 : return NULL;
137 0 : }
138 :
139 1404 : return out;
140 1404 : }
141 :
142 : FD_FN_PURE fd_prog_versions_t
143 : fd_prog_versions( fd_features_t const * features,
144 30745 : ulong slot ) {
145 30745 : int disable_v0 = FD_FEATURE_ACTIVE( slot, features, disable_sbpf_v0_execution );
146 30745 : int reenable_v0 = FD_FEATURE_ACTIVE( slot, features, reenable_sbpf_v0_execution );
147 30745 : int enable_v0 = !disable_v0 || reenable_v0;
148 30745 : int enable_v1 = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v1_deployment_and_execution );
149 30745 : int enable_v2 = FD_FEATURE_ACTIVE( slot, features, enable_sbpf_v2_deployment_and_execution );
150 :
151 30745 : fd_prog_versions_t v = {0};
152 30745 : v.min_sbpf_version = enable_v0 ? FD_SBPF_V0 : FD_SBPF_V2;
153 30745 : if( enable_v2 ) {
154 1410 : v.max_sbpf_version = FD_SBPF_V2;
155 29335 : } else if( enable_v1 ) {
156 268 : v.max_sbpf_version = FD_SBPF_V1;
157 29067 : } else {
158 29067 : v.max_sbpf_version = FD_SBPF_V0;
159 29067 : }
160 30745 : return v;
161 30745 : }
162 :
163 :
164 : fd_prog_load_env_t *
165 : fd_prog_load_env_from_bank( fd_prog_load_env_t * env,
166 6803 : fd_bank_t const * bank ) {
167 6803 : *env = (fd_prog_load_env_t) {
168 6803 : .features = fd_bank_features_query( bank ),
169 6803 : .slot = fd_bank_slot_get ( bank ),
170 6803 : .epoch = fd_bank_epoch_get ( bank ),
171 6803 : .epoch_slot0 = fd_epoch_slot0( fd_bank_epoch_schedule_query( bank ), fd_bank_epoch_get( bank ) )
172 6803 : };
173 6803 : return env;
174 6803 : }
|