Line data Source code
1 : #include "fd_accdb_svm.h"
2 : #include "sysvar/fd_sysvar_rent.h"
3 : #include "program/fd_bpf_loader_program.h"
4 : #include "program/fd_builtin_programs.h"
5 : #include "program/fd_program_util.h"
6 : #include "fd_runtime_stack.h"
7 : #include "fd_pubkey_utils.h"
8 : #include "fd_system_ids.h"
9 : #include "../../ballet/sha256/fd_sha256.h"
10 : #include "../../ballet/sbpf/fd_sbpf_loader.h"
11 : #include "../progcache/fd_prog_load.h"
12 : #include "../vm/fd_vm.h"
13 :
14 : static fd_pubkey_t
15 28 : get_program_data_address( fd_pubkey_t const * program_addr ) {
16 28 : uchar const * seed = program_addr->uc;
17 28 : ulong seed_sz = 32UL;
18 28 : fd_pubkey_t out;
19 28 : uint custom_err;
20 28 : uchar out_bump_seed;
21 28 : int err = fd_pubkey_find_program_address( &fd_solana_bpf_loader_upgradeable_program_id, 1UL, &seed, &seed_sz, &out, &out_bump_seed, &custom_err );
22 28 : if( FD_UNLIKELY( err ) ) {
23 : /* https://github.com/anza-xyz/solana-sdk/blob/address%40v2.1.0/address/src/syscalls.rs#L277-L279 */
24 0 : FD_LOG_ERR(( "Unable to find a viable program address bump seed" ));
25 0 : }
26 28 : return out;
27 28 : }
28 :
29 : fd_tmp_account_t *
30 : tmp_account_new( fd_tmp_account_t * acc,
31 28 : ulong acc_sz ) {
32 28 : acc->data_sz = acc_sz;
33 28 : fd_memset( acc->data, 0, acc_sz );
34 28 : acc->lamports = 0UL;
35 28 : acc->executable = 0;
36 28 : fd_memset( acc->owner.uc, 0, 32UL );
37 28 : fd_memset( acc->pubkey.uc, 0, 32UL );
38 28 : return acc;
39 28 : }
40 :
41 : fd_tmp_account_t *
42 : tmp_account_read( fd_tmp_account_t * acc,
43 : fd_accdb_t * accdb,
44 : fd_accdb_fork_id_t fork_id,
45 28 : fd_pubkey_t const * addr ) {
46 28 : fd_acc_t db_acc = fd_accdb_read_one( accdb, fork_id, addr->uc );
47 28 : if( FD_UNLIKELY( !db_acc.lamports ) ) {
48 28 : fd_accdb_unread_one( accdb, &db_acc );
49 28 : return NULL;
50 28 : }
51 :
52 0 : acc->lamports = db_acc.lamports;
53 0 : fd_memcpy( acc->owner.uc, db_acc.owner, 32UL );
54 0 : acc->executable = db_acc.executable;
55 0 : fd_memcpy( acc->data, db_acc.data, db_acc.data_len );
56 0 : acc->data_sz = db_acc.data_len;
57 0 : acc->pubkey = *addr;
58 :
59 0 : fd_accdb_unread_one( accdb, &db_acc );
60 0 : return acc;
61 28 : }
62 :
63 : /* pd_write must be 1 when acc is a programdata account being written
64 : with program_data.slot == the current slot. */
65 :
66 : void
67 : tmp_account_store( fd_bank_t * bank,
68 : fd_accdb_t * accdb,
69 : fd_tmp_account_t * acc,
70 : fd_capture_ctx_t * capture_ctx,
71 0 : int pd_write ) {
72 0 : if( FD_UNLIKELY( fd_pubkey_eq( &acc->pubkey, &fd_solana_system_program_id ) ) ) FD_LOG_ERR(( "attempted to write to the system program account" ));
73 :
74 0 : fd_accdb_svm_update_t update[1];
75 0 : fd_acc_t db_acc = fd_accdb_svm_open_rw( bank, accdb, update, &acc->pubkey, 1 );
76 :
77 0 : db_acc.executable = acc->executable;
78 0 : fd_memcpy( db_acc.owner, acc->owner.uc, 32UL );
79 0 : db_acc.lamports = acc->lamports;
80 0 : fd_memcpy( db_acc.data, acc->data, acc->data_sz );
81 0 : db_acc.data_len = acc->data_sz;
82 0 : db_acc.pd_write = pd_write;
83 :
84 0 : fd_accdb_svm_close_rw( bank, accdb, capture_ctx, &db_acc, update );
85 0 : }
86 :
87 : /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_core_bpf.rs#L12 */
88 :
89 : struct target_core_bpf {
90 : fd_pubkey_t program_address;
91 : fd_tmp_account_t * program_data_account;
92 : fd_pubkey_t upgrade_authority_address;
93 : uint has_upgrade_authority_address : 1;
94 : };
95 :
96 : typedef struct target_core_bpf target_core_bpf_t;
97 :
98 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L19 */
99 :
100 : struct target_builtin {
101 : fd_tmp_account_t * program_account;
102 : fd_pubkey_t program_data_address;
103 : ulong program_data_account_lamports;
104 : };
105 :
106 : typedef struct target_builtin target_builtin_t;
107 :
108 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L25-L91 */
109 :
110 : target_builtin_t *
111 : target_builtin_new_checked( target_builtin_t * target_builtin,
112 : fd_pubkey_t const * program_address,
113 : int migration_target,
114 : int relax_programdata_account_check_migration,
115 : fd_accdb_t * accdb,
116 : fd_accdb_fork_id_t fork_id,
117 28 : fd_runtime_stack_t * runtime_stack ) {
118 :
119 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L31-L53 */
120 :
121 28 : fd_tmp_account_t * program_account = &runtime_stack->bpf_migration->program_account;
122 28 : switch( migration_target ) {
123 0 : case FD_CORE_BPF_MIGRATION_TARGET_BUILTIN:
124 0 : if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, fork_id, program_address ) ) ) {
125 : /* CoreBpfMigrationError::AccountNotFound(*program_address) */
126 0 : return NULL;
127 0 : }
128 0 : if( FD_UNLIKELY( 0!=memcmp( program_account->owner.uc, &fd_solana_native_loader_id, 32 ) ) ) {
129 : /* CoreBpfMigrationError::IncorrectOwner(*program_address) */
130 0 : return NULL;
131 0 : }
132 0 : break;
133 28 : case FD_CORE_BPF_MIGRATION_TARGET_STATELESS: {
134 : /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
135 28 : if( FD_UNLIKELY( fd_accdb_exists( accdb, fork_id, program_address->uc ) ) ) return NULL;
136 28 : break;
137 28 : }
138 28 : default:
139 0 : FD_LOG_ERR(( "invalid migration_target %d", migration_target ));
140 28 : }
141 :
142 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L55 */
143 :
144 28 : fd_pubkey_t program_data_address = get_program_data_address( program_address );
145 :
146 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L57-L82 */
147 :
148 28 : ulong program_data_account_lamports = 0UL;
149 28 : do {
150 : /* Program data account should not exist */
151 28 : fd_acc_t progdata = fd_accdb_read_one( accdb, fork_id, program_data_address.uc );
152 28 : int progdata_exists = !!progdata.lamports;
153 28 : if( FD_UNLIKELY( !progdata_exists ) ) fd_accdb_unread_one( accdb, &progdata );
154 :
155 : /* SIMD-0444: relax_programdata_account_check_migration
156 : https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L57-L70 */
157 28 : if( relax_programdata_account_check_migration ) {
158 : /* The program data account should not exist, but a system
159 : account with funded lamports is acceptable. */
160 26 : if( FD_UNLIKELY( progdata_exists ) ) {
161 0 : if( FD_UNLIKELY( !fd_pubkey_eq( (fd_pubkey_t*)progdata.owner, &fd_solana_system_program_id ) ) ) {
162 : /* CoreBpfMigrationError::ProgramHasDataAccount(*program_address) */
163 0 : fd_accdb_unread_one( accdb, &progdata );
164 0 : return NULL;
165 0 : } else {
166 0 : program_data_account_lamports = progdata.lamports;
167 0 : fd_accdb_unread_one( accdb, &progdata );
168 0 : }
169 0 : }
170 26 : } else {
171 : /* If relax_programdata_account_check_migration is not enabled,
172 : we do not allow the program data account to exist at all. */
173 2 : if( FD_UNLIKELY( progdata_exists ) ) {
174 : /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
175 0 : fd_accdb_unread_one( accdb, &progdata );
176 0 : return NULL;
177 0 : }
178 2 : }
179 28 : } while(0);
180 :
181 : /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L63-L67 */
182 :
183 28 : *target_builtin = (target_builtin_t) {
184 28 : .program_account = program_account,
185 28 : .program_data_address = program_data_address,
186 28 : .program_data_account_lamports = program_data_account_lamports
187 28 : };
188 28 : return target_builtin;
189 28 : }
190 :
191 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/target_core_bpf.rs#L26-L93 */
192 : static target_core_bpf_t *
193 : target_core_bpf_new_checked( target_core_bpf_t * target_core_bpf,
194 : fd_pubkey_t const * program_address,
195 : fd_accdb_t * accdb,
196 : fd_accdb_fork_id_t fork_id,
197 0 : fd_runtime_stack_t * runtime_stack ) {
198 0 : fd_pubkey_t program_data_address = get_program_data_address( program_address );
199 :
200 : /* The program account should exist */
201 0 : fd_tmp_account_t * program_account = &runtime_stack->bpf_migration->program_account;
202 0 : if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, fork_id, program_address ) ) ) {
203 0 : return NULL;
204 0 : }
205 :
206 : /* The program account should be owned by the upgradeable loader */
207 0 : if( FD_UNLIKELY( 0!=memcmp( &program_account->owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) ) ) ) {
208 0 : return NULL;
209 0 : }
210 :
211 : /* The program account should be executable */
212 0 : if( FD_UNLIKELY( !program_account->executable ) ) {
213 0 : return NULL;
214 0 : }
215 :
216 : /* Decode and validate program account state */
217 0 : fd_bpf_state_t program_state[1];
218 0 : if( FD_UNLIKELY( FD_EXECUTOR_INSTR_SUCCESS!=fd_bpf_loader_program_get_state2( program_account->data, program_account->data_sz, program_state ) ) ) {
219 0 : return NULL;
220 0 : }
221 0 : if( FD_UNLIKELY( program_state->discriminant!=FD_BPF_STATE_PROGRAM ) ) {
222 0 : return NULL;
223 0 : }
224 0 : if( FD_UNLIKELY( 0!=memcmp( &program_state->inner.program.programdata_address, &program_data_address, sizeof(fd_pubkey_t) ) ) ) {
225 0 : return NULL;
226 0 : }
227 :
228 : /* The program data account should exist */
229 0 : fd_tmp_account_t * program_data_account = &runtime_stack->bpf_migration->new_target_program;
230 0 : if( FD_UNLIKELY( !tmp_account_read( program_data_account, accdb, fork_id, &program_data_address ) ) ) {
231 0 : return NULL;
232 0 : }
233 :
234 : /* The program data account should be owned by the upgradeable loader */
235 0 : if( FD_UNLIKELY( 0!=memcmp( &program_data_account->owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) ) ) ) {
236 0 : return NULL;
237 0 : }
238 :
239 : /* Decode and validate program data account state */
240 0 : fd_bpf_state_t programdata_state[1];
241 0 : if( FD_UNLIKELY( FD_EXECUTOR_INSTR_SUCCESS!=fd_bpf_loader_program_get_state2( program_data_account->data, program_data_account->data_sz, programdata_state ) ) ) {
242 0 : return NULL;
243 0 : }
244 0 : if( FD_UNLIKELY( programdata_state->discriminant!=FD_BPF_STATE_PROGRAM_DATA ) ) {
245 0 : return NULL;
246 0 : }
247 :
248 : /* Extract upgrade authority from program data state */
249 0 : fd_pubkey_t upgrade_authority_address;
250 0 : if( programdata_state->inner.program_data.has_upgrade_authority_address ) {
251 0 : upgrade_authority_address = programdata_state->inner.program_data.upgrade_authority_address;
252 0 : } else {
253 0 : fd_memset( &upgrade_authority_address, 0, sizeof(fd_pubkey_t) );
254 0 : }
255 :
256 0 : *target_core_bpf = (target_core_bpf_t) {
257 0 : .program_address = *program_address,
258 0 : .program_data_account = program_data_account,
259 0 : .upgrade_authority_address = upgrade_authority_address,
260 0 : .has_upgrade_authority_address = (uint)!!programdata_state->inner.program_data.has_upgrade_authority_address
261 0 : };
262 0 : return target_core_bpf;
263 0 : }
264 :
265 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L25-L82
266 :
267 : Agave uses a separate TargetBpfV2 struct, but it has the
268 : same layout as target_builtin_t so we reuse that. */
269 : static target_builtin_t *
270 : target_bpf_v2_new_checked( target_builtin_t * target_bpf_v2,
271 : fd_pubkey_t const * program_address,
272 : int allow_prefunded,
273 : fd_accdb_t * accdb,
274 : fd_accdb_fork_id_t fork_id,
275 0 : fd_runtime_stack_t * runtime_stack ) {
276 :
277 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L30-L33 */
278 0 : fd_tmp_account_t * program_account = &runtime_stack->bpf_migration->program_account;
279 0 : if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, fork_id, program_address ) ) ) {
280 : /* CoreBpfMigrationError::AccountNotFound(*program_address) */
281 0 : return NULL;
282 0 : }
283 :
284 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L35-L38 */
285 0 : if( FD_UNLIKELY( 0!=memcmp( &program_account->owner, &fd_solana_bpf_loader_program_id, sizeof(fd_pubkey_t) ) ) ) {
286 : /* CoreBpfMigrationError::IncorrectOwner(*program_address) */
287 0 : return NULL;
288 0 : }
289 :
290 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L40-L45 */
291 0 : if( FD_UNLIKELY( !program_account->executable ) ) {
292 : /* CoreBpfMigrationError::ProgramAccountNotExecutable(*program_address) */
293 0 : return NULL;
294 0 : }
295 :
296 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L47 */
297 0 : fd_pubkey_t program_data_address = get_program_data_address( program_address );
298 :
299 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L49-L74 */
300 0 : ulong program_data_account_lamports = 0UL;
301 0 : do {
302 0 : fd_acc_t acc = fd_accdb_read_one( accdb, fork_id, program_data_address.uc );
303 0 : int progdata_exists = !!acc.lamports;
304 0 : if( FD_UNLIKELY( !progdata_exists ) ) fd_accdb_unread_one( accdb, &acc );
305 :
306 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L49-L74 */
307 0 : if( FD_LIKELY( allow_prefunded ) ) {
308 : /* The program data account should not exist, but a system
309 : account with funded lamports is acceptable.
310 :
311 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L50-L61 */
312 0 : if( FD_UNLIKELY( progdata_exists ) ) {
313 0 : if( FD_UNLIKELY( !fd_pubkey_eq( (fd_pubkey_t*)acc.owner, &fd_solana_system_program_id ) ) ) {
314 : /* CoreBpfMigrationError::ProgramHasDataAccount(*program_address) */
315 0 : fd_accdb_unread_one( accdb, &acc );
316 0 : return NULL;
317 0 : } else {
318 0 : program_data_account_lamports = acc.lamports;
319 0 : fd_accdb_unread_one( accdb, &acc );
320 0 : }
321 0 : }
322 0 : } else {
323 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L62-L74 */
324 0 : if( FD_UNLIKELY( progdata_exists ) ) {
325 : /* CoreBpfMigrationError::ProgramHasDataAccount(*program_address) */
326 0 : fd_accdb_unread_one( accdb, &acc );
327 0 : return NULL;
328 0 : }
329 0 : }
330 0 : } while(0);
331 :
332 0 : *target_bpf_v2 = (target_builtin_t) {
333 0 : .program_account = program_account,
334 0 : .program_data_address = program_data_address,
335 0 : .program_data_account_lamports = program_data_account_lamports
336 0 : };
337 0 : return target_bpf_v2;
338 0 : }
339 :
340 : /* This function contains the deployment checks that are equivalent to
341 : Agave's directly_invoke_loader_v3_deploy.
342 :
343 : There is no direct equivalent in Agave to this function, because
344 : we are not updating the program cache here. However, we do the same
345 : checks that our program cache does upon deployment.
346 :
347 : This is safe because the bpf migration code runs at the epoch
348 : boundary when the migration feature activates, before transaction
349 : execution. The feature activation selects a new program-cache
350 : revision, so no explicit cache update is needed here.
351 :
352 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L120-L218 */
353 : static int
354 : fd_directly_invoke_loader_v3_deploy_checks( fd_bank_t const * bank,
355 : fd_runtime_stack_t * runtime_stack,
356 : uchar const * elf,
357 0 : ulong elf_sz ) {
358 0 : fd_features_t const * features = &bank->f.features;
359 0 : ulong slot = bank->f.slot;
360 :
361 : /* ELF verification with deploy checks enabled */
362 0 : fd_prog_versions_t versions = fd_prog_versions( features, slot );
363 0 : fd_sbpf_loader_config_t loader_config = {
364 0 : .elf_deploy_checks = 1,
365 0 : .sbpf_min_version = versions.min_sbpf_version,
366 0 : .sbpf_max_version = versions.max_sbpf_version,
367 0 : };
368 0 : fd_sbpf_elf_info_t elf_info[1];
369 0 : if( FD_UNLIKELY( fd_sbpf_elf_peek( elf_info, elf, elf_sz, &loader_config )!=FD_SBPF_ELF_SUCCESS ) ) return 1;
370 :
371 : /* Setup program (includes calldests) */
372 0 : fd_sbpf_program_t * prog = fd_sbpf_program_new(
373 0 : runtime_stack->bpf_migration->progcache_validate.sbpf_footprint,
374 0 : elf_info,
375 0 : runtime_stack->bpf_migration->progcache_validate.rodata );
376 0 : if( FD_UNLIKELY( !prog ) ) return 1;
377 :
378 0 : fd_sbpf_syscalls_t _syscalls[ FD_SBPF_SYSCALLS_SLOT_CNT ];
379 0 : fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_join( fd_sbpf_syscalls_new( _syscalls ) );
380 0 : if( FD_UNLIKELY( !syscalls ) ) return 1;
381 0 : if( FD_UNLIKELY( fd_vm_syscall_register_slot( syscalls, slot, features, /* is_deploy */ 1 )!=FD_VM_SUCCESS ) ) return 1;
382 :
383 : /* fd_sbpf_program_load checks */
384 0 : if( FD_UNLIKELY( fd_sbpf_program_load(
385 0 : prog,
386 0 : elf,
387 0 : elf_sz,
388 0 : syscalls,
389 0 : &loader_config,
390 0 : runtime_stack->bpf_migration->progcache_validate.programdata,
391 0 : sizeof(runtime_stack->bpf_migration->progcache_validate.programdata) ) ) ) return 1;
392 :
393 : /* fd_vm_validate checks */
394 0 : fd_vm_t _vm[1];
395 0 : fd_vm_t * vm = fd_vm_join( fd_vm_new( _vm ) );
396 0 : if( FD_UNLIKELY( !vm ) ) return 1;
397 0 : vm = fd_vm_init( vm,
398 0 : NULL,
399 0 : 0UL,
400 0 : 0UL,
401 0 : prog->rodata,
402 0 : prog->rodata_sz,
403 0 : prog->text,
404 0 : prog->info.text_cnt,
405 0 : prog->info.text_off,
406 0 : prog->info.text_sz,
407 0 : prog->entry_pc,
408 0 : prog->calldests,
409 0 : elf_info->sbpf_version,
410 0 : syscalls,
411 0 : NULL,
412 0 : NULL,
413 0 : NULL,
414 0 : 0U,
415 0 : NULL,
416 0 : 0,
417 0 : FD_FEATURE_ACTIVE( slot, features, account_data_direct_mapping ),
418 0 : FD_FEATURE_ACTIVE( slot, features, syscall_parameter_address_restrictions ),
419 0 : FD_FEATURE_ACTIVE( slot, features, virtual_address_space_adjustments ),
420 0 : 0,
421 0 : 0UL );
422 0 : if( FD_UNLIKELY( !vm ) ) return 1;
423 0 : if( FD_UNLIKELY( fd_vm_validate( vm )!=FD_VM_SUCCESS ) ) return 1;
424 :
425 0 : return FD_EXECUTOR_INSTR_SUCCESS;
426 0 : }
427 :
428 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L51-L75 */
429 :
430 : static fd_tmp_account_t *
431 : source_buffer_new_checked( fd_tmp_account_t * acc,
432 : fd_accdb_t * accdb,
433 : fd_accdb_fork_id_t fork_id,
434 : fd_pubkey_t const * pubkey,
435 28 : fd_hash_t const * verified_build_hash ) {
436 :
437 28 : if( FD_UNLIKELY( !tmp_account_read( acc, accdb, fork_id, pubkey ) ) ) {
438 : /* CoreBpfMigrationError::AccountNotFound(*buffer_address) */
439 28 : return NULL;
440 28 : }
441 :
442 0 : if( FD_UNLIKELY( 0!=memcmp( acc->owner.uc, &fd_solana_bpf_loader_upgradeable_program_id, 32 ) ) ) {
443 : /* CoreBpfMigrationError::IncorrectOwner(*buffer_address) */
444 0 : return NULL;
445 0 : }
446 :
447 0 : if( acc->data_sz < BUFFER_METADATA_SIZE ) {
448 : /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
449 0 : return NULL;
450 0 : }
451 :
452 0 : fd_bpf_state_t state[1];
453 0 : if( FD_UNLIKELY( fd_bpf_state_decode( state, acc->data, BUFFER_METADATA_SIZE ) ) ) {
454 0 : return NULL;
455 0 : }
456 :
457 0 : if( FD_UNLIKELY( state->discriminant!=FD_BPF_STATE_BUFFER ) ) {
458 : /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
459 0 : return NULL;
460 0 : }
461 :
462 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L71 */
463 0 : if( verified_build_hash ) {
464 : /* Strip trailing zero-padding before hashing
465 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L63 */
466 0 : uchar const * data = (uchar const *)acc->data;
467 0 : ulong offset = BUFFER_METADATA_SIZE;
468 0 : ulong end_offset = acc->data_sz;
469 0 : while( end_offset>offset && data[end_offset-1]==0 ) end_offset--;
470 0 : uchar const * buffer_program_data = data + offset;
471 0 : ulong buffer_program_data_sz = end_offset - offset;
472 :
473 0 : fd_hash_t hash;
474 0 : fd_sha256_hash( buffer_program_data, buffer_program_data_sz, hash.uc );
475 0 : if( FD_UNLIKELY( 0!=memcmp( hash.uc, verified_build_hash->uc, FD_HASH_FOOTPRINT ) ) ) {
476 : /* CoreBpfMigrationError::BuildHashMismatch */
477 0 : return NULL;
478 0 : }
479 0 : }
480 :
481 0 : return acc;
482 0 : }
483 :
484 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L82-L95 */
485 :
486 : static fd_tmp_account_t *
487 : new_target_program_account( fd_tmp_account_t * acc,
488 : target_builtin_t const * target,
489 0 : fd_rent_t const * rent ) {
490 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L86-L88 */
491 0 : fd_bpf_state_t state = {
492 0 : .discriminant = FD_BPF_STATE_PROGRAM,
493 0 : .inner = {
494 0 : .program = {
495 0 : .programdata_address = target->program_data_address,
496 0 : }
497 0 : }
498 0 : };
499 :
500 0 : ulong state_sz = fd_bpf_state_size( &state );
501 0 : tmp_account_new( acc, state_sz );
502 0 : acc->lamports = fd_rent_exempt_minimum_balance( rent, SIZE_OF_PROGRAM );
503 0 : acc->executable = 1;
504 0 : memcpy( acc->owner.uc, fd_solana_bpf_loader_upgradeable_program_id.uc, sizeof(fd_pubkey_t) );
505 :
506 0 : ulong out_sz = 0UL;
507 0 : if( FD_UNLIKELY( fd_bpf_state_encode( &state, acc->data, state_sz, &out_sz ) ) ) {
508 0 : FD_LOG_ERR(( "fd_bpf_state_encode failed" ));
509 0 : }
510 :
511 0 : return acc;
512 0 : }
513 :
514 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L108-L153 */
515 : static fd_tmp_account_t *
516 : new_target_program_data_account( fd_tmp_account_t * acc,
517 : fd_tmp_account_t const * source,
518 : fd_pubkey_t const * upgrade_authority_address,
519 : fd_rent_t const * rent,
520 0 : ulong slot ) {
521 0 : ulong const buffer_metadata_sz = BUFFER_METADATA_SIZE;
522 :
523 0 : if( FD_UNLIKELY( source->data_sz < buffer_metadata_sz ) )
524 0 : return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
525 :
526 0 : fd_bpf_state_t state;
527 0 : if( FD_UNLIKELY( fd_bpf_state_decode( &state, source->data, buffer_metadata_sz ) ) ) {
528 0 : return NULL;
529 0 : }
530 :
531 0 : if( FD_UNLIKELY( state.discriminant!=FD_BPF_STATE_BUFFER ) )
532 0 : return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
533 :
534 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L118-L125 */
535 0 : if( upgrade_authority_address ) {
536 0 : if( FD_UNLIKELY( !state.inner.buffer.has_authority_address ||
537 0 : !fd_pubkey_eq( upgrade_authority_address, &state.inner.buffer.authority_address ) ) ) {
538 0 : return NULL; /* CoreBpfMigrationError::UpgradeAuthorityMismatch */
539 0 : }
540 0 : }
541 :
542 0 : void const * elf = (uchar const *)source->data + buffer_metadata_sz;
543 0 : ulong elf_sz = /* */source->data_sz - buffer_metadata_sz;
544 :
545 0 : ulong space = PROGRAMDATA_METADATA_SIZE + elf_sz;
546 0 : ulong lamports = fd_rent_exempt_minimum_balance( rent, space );
547 0 : fd_pubkey_t owner = fd_solana_bpf_loader_upgradeable_program_id;
548 :
549 0 : fd_bpf_state_t programdata_meta = {
550 0 : .discriminant = FD_BPF_STATE_PROGRAM_DATA,
551 0 : .inner = {
552 0 : .program_data = {
553 0 : .slot = slot,
554 0 : .has_upgrade_authority_address = !!upgrade_authority_address,
555 0 : .upgrade_authority_address = upgrade_authority_address ? *upgrade_authority_address : (fd_pubkey_t){{0}}
556 0 : }
557 0 : }
558 0 : };
559 :
560 0 : tmp_account_new( acc, space );
561 0 : acc->lamports = lamports;
562 0 : memcpy( acc->owner.uc, owner.uc, sizeof(fd_pubkey_t) );
563 0 : ulong out_sz = 0UL;
564 0 : if( FD_UNLIKELY( fd_bpf_state_encode( &programdata_meta, acc->data, PROGRAMDATA_METADATA_SIZE, &out_sz ) ) ) {
565 0 : FD_LOG_ERR(( "fd_bpf_state_encode failed" ));
566 0 : }
567 0 : fd_memcpy( (uchar *)acc->data+PROGRAMDATA_METADATA_SIZE, elf, elf_sz );
568 :
569 0 : return acc;
570 0 : }
571 :
572 : void
573 : migrate_builtin_to_core_bpf1( fd_core_bpf_migration_config_t const * config,
574 : fd_accdb_t * accdb,
575 : fd_bank_t * bank,
576 : fd_runtime_stack_t * runtime_stack,
577 : fd_pubkey_t const * builtin_program_id,
578 28 : fd_capture_ctx_t * capture_ctx ) {
579 :
580 28 : tmp_account_new( &runtime_stack->bpf_migration->program_account, 0UL );
581 :
582 28 : target_builtin_t target[1];
583 28 : if( FD_UNLIKELY( !target_builtin_new_checked(
584 28 : target,
585 28 : builtin_program_id,
586 28 : config->migration_target,
587 28 : FD_FEATURE_ACTIVE_BANK( bank, relax_programdata_account_check_migration ),
588 28 : accdb,
589 28 : bank->accdb_fork_id,
590 28 : runtime_stack ) ) )
591 0 : return;
592 :
593 28 : fd_memset( &runtime_stack->bpf_migration->source, 0, sizeof(runtime_stack->bpf_migration->source ) );
594 28 : fd_memset( &runtime_stack->bpf_migration->new_target_program, 0, sizeof(runtime_stack->bpf_migration->new_target_program ) );
595 28 : fd_memset( &runtime_stack->bpf_migration->new_target_program_data, 0, sizeof(runtime_stack->bpf_migration->new_target_program_data) );
596 28 : fd_memset( &runtime_stack->bpf_migration->empty, 0, sizeof(runtime_stack->bpf_migration->empty ) );
597 28 : fd_memset( &runtime_stack->bpf_migration->progcache_validate, 0, sizeof(runtime_stack->bpf_migration->progcache_validate ) );
598 :
599 : /* https://github.com/anza-xyz/agave/blob/8da849e919e0762f6bfc9ca17ac2339c7a003a0e/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L232-L240 */
600 28 : fd_tmp_account_t * source = &runtime_stack->bpf_migration->source;
601 28 : if( FD_UNLIKELY( !source_buffer_new_checked(
602 28 : source,
603 28 : accdb,
604 28 : bank->accdb_fork_id,
605 28 : config->source_buffer_address,
606 28 : config->verified_build_hash ) ) )
607 28 : return;
608 : /* This should never happen after core_bpf_hash_validation is
609 : activated, which is a pre-req for all future BPF program upgrades. */
610 0 : if( FD_UNLIKELY( !config->verified_build_hash ) ) {
611 0 : FD_BASE58_ENCODE_32_BYTES( config->source_buffer_address->uc, buffer_b58 );
612 0 : FD_LOG_ERR(( "missing verified build hash for source buffer %s", buffer_b58 ));
613 0 : }
614 :
615 0 : fd_rent_t const * rent = &bank->f.rent;
616 0 : ulong const slot = bank->f.slot;
617 :
618 0 : fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration->new_target_program;
619 0 : if( FD_UNLIKELY( !new_target_program_account(
620 0 : new_target_program,
621 0 : target,
622 0 : rent ) ) )
623 0 : return;
624 0 : new_target_program->pubkey = *builtin_program_id;
625 :
626 0 : fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration->new_target_program_data;
627 0 : if( FD_UNLIKELY( !new_target_program_data_account(
628 0 : new_target_program_data,
629 0 : source,
630 0 : config->upgrade_authority_address,
631 0 : rent,
632 0 : slot ) ) )
633 0 : return;
634 0 : new_target_program_data->pubkey = target->program_data_address;
635 :
636 0 : ulong old_data_sz;
637 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
638 :
639 0 : ulong new_data_sz;
640 0 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return;
641 :
642 0 : FD_DCHECK_CRIT( new_target_program_data->data_sz>=PROGRAMDATA_METADATA_SIZE, "undersize account" );
643 : /* FIXME call fd_directly_invoke_loader_v3_deploy */
644 :
645 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L267-L281 */
646 0 : ulong lamports_to_burn;
647 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->lamports, source->lamports, &lamports_to_burn ) ) ) return;
648 0 : if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) ) return;
649 :
650 0 : ulong lamports_to_fund;
651 0 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->lamports, new_target_program_data->lamports, &lamports_to_fund ) ) ) return;
652 :
653 : /* Write back accounts */
654 0 : tmp_account_store( bank, accdb, new_target_program, capture_ctx, 0 );
655 0 : tmp_account_store( bank, accdb, new_target_program_data, capture_ctx, 1 );
656 0 : fd_tmp_account_t * empty = &runtime_stack->bpf_migration->empty;
657 0 : tmp_account_new( empty, 0UL );
658 0 : empty->pubkey = source->pubkey;
659 0 : tmp_account_store( bank, accdb, empty, capture_ctx, 0 );
660 :
661 : /* FIXME "remove the built-in program from the bank's list of builtins" */
662 : /* FIXME "update account data size delta" */
663 0 : }
664 :
665 : /* Mimics migrate_builtin_to_core_bpf().
666 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#215-303 */
667 : void
668 : fd_migrate_builtin_to_core_bpf( fd_bank_t * bank,
669 : fd_accdb_t * accdb,
670 : fd_runtime_stack_t * runtime_stack,
671 : fd_core_bpf_migration_config_t const * config,
672 28 : fd_capture_ctx_t * capture_ctx ) {
673 28 : migrate_builtin_to_core_bpf1( config, accdb, bank, runtime_stack, config->builtin_program_id, capture_ctx );
674 28 : }
675 :
676 : /* Mimics upgrade_core_bpf_program().
677 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L319-L377 */
678 : void
679 : fd_upgrade_core_bpf_program( fd_bank_t * bank,
680 : fd_accdb_t * accdb,
681 : fd_runtime_stack_t * runtime_stack,
682 : fd_pubkey_t const * builtin_program_id,
683 : fd_pubkey_t const * source_buffer_address,
684 : fd_hash_t const * verified_build_hash,
685 0 : fd_capture_ctx_t * capture_ctx ) {
686 0 : fd_memset( runtime_stack->bpf_migration, 0, sizeof(fd_runtime_stack_bpf_migration_t) );
687 :
688 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L327 */
689 0 : target_core_bpf_t target[1];
690 0 : if( FD_UNLIKELY( !target_core_bpf_new_checked( target, builtin_program_id, accdb, bank->accdb_fork_id, runtime_stack ) ) ) {
691 0 : return;
692 0 : }
693 :
694 : /* https://github.com/anza-xyz/agave/blob/8da849e919e0762f6bfc9ca17ac2339c7a003a0e/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L330-L338 */
695 0 : fd_tmp_account_t * source = &runtime_stack->bpf_migration->source;
696 0 : if( FD_UNLIKELY( !source_buffer_new_checked(
697 0 : source,
698 0 : accdb,
699 0 : bank->accdb_fork_id,
700 0 : source_buffer_address,
701 0 : verified_build_hash ) ) ) {
702 0 : return;
703 0 : }
704 :
705 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L118-L125 */
706 0 : if( target->has_upgrade_authority_address ) {
707 0 : fd_bpf_state_t buffer_state[1];
708 0 : if( FD_UNLIKELY( fd_bpf_state_decode( buffer_state, source->data, BUFFER_METADATA_SIZE ) ||
709 0 : buffer_state->discriminant!=FD_BPF_STATE_BUFFER ||
710 0 : !buffer_state->inner.buffer.has_authority_address ||
711 0 : !fd_pubkey_eq( &target->upgrade_authority_address, &buffer_state->inner.buffer.authority_address ) ) ) {
712 : /* CoreBpfMigrationError::UpgradeAuthorityMismatch */
713 0 : FD_LOG_WARNING(( "core-BPF program upgrade aborted at slot %lu: source buffer authority does not match the target program's upgrade authority",
714 0 : bank->f.slot ));
715 0 : return;
716 0 : }
717 0 : }
718 :
719 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L331-L332 */
720 0 : fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration->new_target_program_data;
721 0 : fd_pubkey_t program_data_address = get_program_data_address( builtin_program_id );
722 :
723 0 : ulong program_data_len = source->data_sz - BUFFER_METADATA_SIZE;
724 0 : ulong new_account_size = PROGRAMDATA_METADATA_SIZE + program_data_len;
725 :
726 0 : tmp_account_new( new_target_program_data, new_account_size );
727 0 : new_target_program_data->pubkey = program_data_address;
728 :
729 0 : fd_rent_t const * rent = &bank->f.rent;
730 0 : new_target_program_data->lamports = fd_rent_exempt_minimum_balance( rent, new_account_size );
731 0 : new_target_program_data->executable = 0;
732 0 : fd_memcpy( new_target_program_data->owner.uc, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) );
733 :
734 0 : fd_bpf_state_t programdata_state[1] = {{
735 0 : .discriminant = FD_BPF_STATE_PROGRAM_DATA,
736 0 : .inner = { .program_data = {
737 0 : .slot = bank->f.slot,
738 0 : .upgrade_authority_address = target->upgrade_authority_address,
739 0 : .has_upgrade_authority_address = target->has_upgrade_authority_address
740 0 : }}
741 0 : }};
742 :
743 0 : ulong out_sz = 0UL;
744 0 : if( FD_UNLIKELY( fd_bpf_state_encode( programdata_state, new_target_program_data->data, PROGRAMDATA_METADATA_SIZE, &out_sz ) ) ) {
745 0 : return;
746 0 : }
747 :
748 0 : fd_memcpy( new_target_program_data->data + PROGRAMDATA_METADATA_SIZE,
749 0 : source->data + BUFFER_METADATA_SIZE,
750 0 : program_data_len );
751 :
752 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.4/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L339-L346 */
753 0 : ulong old_data_sz;
754 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
755 0 : ulong new_data_sz = new_target_program_data->data_sz;
756 :
757 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.4/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L349-L355 */
758 0 : uchar const * elf = new_target_program_data->data + PROGRAMDATA_METADATA_SIZE;
759 0 : ulong elf_sz = program_data_len;
760 0 : if( FD_UNLIKELY( fd_directly_invoke_loader_v3_deploy_checks( bank, runtime_stack, elf, elf_sz ) ) ) return;
761 :
762 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L359-L364 */
763 0 : ulong lamports_to_burn;
764 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->lamports, source->lamports, &lamports_to_burn ) ) ) return;
765 :
766 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L366-L371 */
767 0 : fd_pubkey_t source_addr = source->pubkey;
768 0 : tmp_account_store( bank, accdb, new_target_program_data, capture_ctx, 1 );
769 :
770 0 : fd_tmp_account_t * empty = &runtime_stack->bpf_migration->empty;
771 0 : tmp_account_new( empty, 0UL );
772 0 : empty->pubkey = source_addr;
773 0 : tmp_account_store( bank, accdb, empty, capture_ctx, 0 );
774 :
775 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L374 */
776 : /* FIXME "update account data size delta" */
777 0 : (void)old_data_sz;
778 0 : (void)new_data_sz;
779 :
780 0 : fd_memset( runtime_stack->bpf_migration, 0, sizeof(fd_runtime_stack_bpf_migration_t) );
781 0 : }
782 :
783 : /* Mimics upgrade_loader_v2_program_with_loader_v3_program().
784 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L402-L474 */
785 : void
786 : fd_upgrade_loader_v2_program_with_loader_v3_program( fd_bank_t * bank,
787 : fd_accdb_t * accdb,
788 : fd_runtime_stack_t * runtime_stack,
789 : fd_pubkey_t const * loader_v2_program_address,
790 : fd_pubkey_t const * source_buffer_address,
791 : fd_hash_t const * verified_build_hash,
792 : int allow_prefunded,
793 0 : fd_capture_ctx_t * capture_ctx ) {
794 0 : fd_memset( runtime_stack->bpf_migration, 0, sizeof(fd_runtime_stack_bpf_migration_t) );
795 :
796 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L411-L412 */
797 0 : target_builtin_t target[1];
798 0 : if( FD_UNLIKELY( !target_bpf_v2_new_checked(
799 0 : target,
800 0 : loader_v2_program_address,
801 0 : allow_prefunded,
802 0 : accdb,
803 0 : bank->accdb_fork_id,
804 0 : runtime_stack ) ) )
805 0 : return;
806 :
807 : /* https://github.com/anza-xyz/agave/blob/8da849e919e0762f6bfc9ca17ac2339c7a003a0e/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L420-L428 */
808 0 : fd_tmp_account_t * source = &runtime_stack->bpf_migration->source;
809 0 : if( FD_UNLIKELY( !source_buffer_new_checked(
810 0 : source,
811 0 : accdb,
812 0 : bank->accdb_fork_id,
813 0 : source_buffer_address,
814 0 : verified_build_hash ) ) )
815 0 : return;
816 :
817 0 : fd_rent_t const * rent = &bank->f.rent;
818 0 : ulong slot = bank->f.slot;
819 :
820 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L416-L417 */
821 0 : fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration->new_target_program;
822 0 : if( FD_UNLIKELY( !new_target_program_account( new_target_program, target, rent ) ) )
823 0 : return;
824 0 : new_target_program->pubkey = *loader_v2_program_address;
825 :
826 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L419-L421 */
827 0 : fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration->new_target_program_data;
828 0 : if( FD_UNLIKELY( !new_target_program_data_account( new_target_program_data, source, NULL, rent, slot ) ) ) {
829 0 : return;
830 0 : }
831 0 : new_target_program_data->pubkey = target->program_data_address;
832 :
833 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L427-L435 */
834 0 : ulong old_data_sz;
835 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
836 :
837 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L432-L435 */
838 0 : ulong new_data_sz;
839 0 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return;
840 :
841 0 : if( FD_UNLIKELY( new_target_program_data->data_sz<PROGRAMDATA_METADATA_SIZE ) ) {
842 0 : FD_LOG_CRIT(( "invariant violation: new target programdata too small" ));
843 0 : }
844 :
845 : /* Agave calls directly_invoke_loader_v3_deploy to deploy the new
846 : program to the program cache. We don't do that, but instead we
847 : perform the same checks as directly_invoke_loader_v3_deploy
848 : without modifying the program cache. We need to do the checks
849 : at this point so that we can fail the upgrade if the ELF is
850 : invalid.
851 :
852 : This is safe because the bpf migration code runs at the epoch
853 : boundary when the migration feature activates, before transaction
854 : execution. The feature activation selects a new program-cache
855 : revision, so no explicit cache update is needed here.
856 :
857 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L437-L443*/
858 0 : uchar const * elf = (uchar const *)new_target_program_data->data + PROGRAMDATA_METADATA_SIZE;
859 0 : ulong elf_sz = new_target_program_data->data_sz - PROGRAMDATA_METADATA_SIZE;
860 0 : if( FD_UNLIKELY( fd_directly_invoke_loader_v3_deploy_checks( bank, runtime_stack, elf, elf_sz ) ) ) return;
861 :
862 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L451-L459 */
863 0 : ulong lamports_to_burn;
864 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->lamports, source->lamports, &lamports_to_burn ) ) ) return;
865 0 : if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) ) return;
866 :
867 0 : ulong lamports_to_fund;
868 0 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->lamports, new_target_program_data->lamports, &lamports_to_fund ) ) ) return;
869 :
870 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L462-L468 */
871 0 : tmp_account_store( bank, accdb, new_target_program, capture_ctx, 0 );
872 0 : tmp_account_store( bank, accdb, new_target_program_data, capture_ctx, 1 );
873 :
874 0 : fd_tmp_account_t * empty = &runtime_stack->bpf_migration->empty;
875 0 : tmp_account_new( empty, 0UL );
876 0 : empty->pubkey = source->pubkey;
877 0 : tmp_account_store( bank, accdb, empty, capture_ctx, 0 );
878 :
879 : /* NB: Agave updates "delta_off_chain", using these two fields,
880 : which is not consensus-critical (only used for Agave stats)
881 : so we don't update this in our migration code or store this in
882 : our bank. */
883 0 : (void)old_data_sz;
884 0 : (void)new_data_sz;
885 :
886 0 : fd_memset( runtime_stack->bpf_migration, 0, sizeof(fd_runtime_stack_bpf_migration_t) );
887 0 : }
|