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