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 9 : get_program_data_address( fd_pubkey_t const * program_addr ) {
16 9 : uchar const * seed = program_addr->uc;
17 9 : ulong seed_sz = 32UL;
18 9 : fd_pubkey_t out;
19 9 : uint custom_err;
20 9 : uchar out_bump_seed;
21 9 : 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 9 : 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 9 : return out;
27 9 : }
28 :
29 : fd_tmp_account_t *
30 : tmp_account_new( fd_tmp_account_t * acc,
31 18 : ulong acc_sz ) {
32 18 : acc->data_sz = acc_sz;
33 18 : fd_memset( acc->data, 0, acc_sz );
34 18 : acc->lamports = 0UL;
35 18 : acc->executable = 0;
36 18 : fd_memset( acc->owner.uc, 0, 32UL );
37 18 : fd_memset( acc->pubkey.uc, 0, 32UL );
38 18 : return acc;
39 18 : }
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 15 : fd_pubkey_t const * addr ) {
46 15 : fd_acc_t db_acc = fd_accdb_read_one( accdb, fork_id, addr->uc );
47 15 : if( FD_UNLIKELY( !db_acc.lamports ) ) {
48 0 : fd_accdb_unread_one( accdb, &db_acc );
49 0 : return NULL;
50 0 : }
51 :
52 15 : acc->lamports = db_acc.lamports;
53 15 : fd_memcpy( acc->owner.uc, db_acc.owner, 32UL );
54 15 : acc->executable = db_acc.executable;
55 15 : fd_memcpy( acc->data, db_acc.data, db_acc.data_len );
56 15 : acc->data_sz = db_acc.data_len;
57 15 : acc->pubkey = *addr;
58 :
59 15 : fd_accdb_unread_one( accdb, &db_acc );
60 15 : return acc;
61 15 : }
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 15 : int pd_write ) {
72 15 : 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 15 : fd_accdb_svm_update_t update[1];
75 15 : fd_acc_t db_acc = fd_accdb_svm_open_rw( bank, accdb, update, &acc->pubkey, 1 );
76 :
77 15 : db_acc.executable = acc->executable;
78 15 : fd_memcpy( db_acc.owner, acc->owner.uc, 32UL );
79 15 : db_acc.lamports = acc->lamports;
80 15 : fd_memcpy( db_acc.data, acc->data, acc->data_sz );
81 15 : db_acc.data_len = acc->data_sz;
82 15 : db_acc.pd_write = pd_write;
83 :
84 15 : fd_accdb_svm_close_rw( bank, accdb, capture_ctx, &db_acc, update );
85 15 : }
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 3 : 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 3 : fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
122 3 : switch( migration_target ) {
123 3 : case FD_CORE_BPF_MIGRATION_TARGET_BUILTIN:
124 3 : 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 3 : 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 3 : break;
133 3 : case FD_CORE_BPF_MIGRATION_TARGET_STATELESS: {
134 : /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
135 0 : if( FD_UNLIKELY( fd_accdb_exists( accdb, fork_id, program_address->uc ) ) ) return NULL;
136 0 : break;
137 0 : }
138 0 : default:
139 0 : FD_LOG_ERR(( "invalid migration_target %d", migration_target ));
140 3 : }
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 3 : 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 3 : ulong program_data_account_lamports = 0UL;
149 3 : do {
150 : /* Program data account should not exist */
151 3 : fd_acc_t progdata = fd_accdb_read_one( accdb, fork_id, program_data_address.uc );
152 3 : int progdata_exists = !!progdata.lamports;
153 3 : 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 3 : 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 3 : if( FD_UNLIKELY( progdata_exists ) ) {
161 3 : 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 3 : } else {
166 3 : program_data_account_lamports = progdata.lamports;
167 3 : fd_accdb_unread_one( accdb, &progdata );
168 3 : }
169 3 : }
170 3 : } 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 0 : 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 0 : }
179 3 : } 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 3 : *target_builtin = (target_builtin_t) {
184 3 : .program_account = program_account,
185 3 : .program_data_address = program_data_address,
186 3 : .program_data_account_lamports = program_data_account_lamports
187 3 : };
188 3 : return target_builtin;
189 3 : }
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 3 : fd_runtime_stack_t * runtime_stack ) {
198 3 : fd_pubkey_t program_data_address = get_program_data_address( program_address );
199 :
200 : /* The program account should exist */
201 3 : fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
202 3 : 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 3 : 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 3 : if( FD_UNLIKELY( !program_account->executable ) ) {
213 0 : return NULL;
214 0 : }
215 :
216 : /* Decode and validate program account state */
217 3 : fd_bpf_state_t program_state[1];
218 3 : 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 3 : if( FD_UNLIKELY( program_state->discriminant!=FD_BPF_STATE_PROGRAM ) ) {
222 0 : return NULL;
223 0 : }
224 3 : 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 3 : fd_tmp_account_t * program_data_account = &runtime_stack->bpf_migration.new_target_program;
230 3 : 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 3 : 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 3 : fd_bpf_state_t programdata_state[1];
241 3 : 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 3 : 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 3 : fd_pubkey_t upgrade_authority_address;
250 3 : if( programdata_state->inner.program_data.has_upgrade_authority_address ) {
251 3 : upgrade_authority_address = programdata_state->inner.program_data.upgrade_authority_address;
252 3 : } else {
253 0 : fd_memset( &upgrade_authority_address, 0, sizeof(fd_pubkey_t) );
254 0 : }
255 :
256 3 : *target_core_bpf = (target_core_bpf_t) {
257 3 : .program_address = *program_address,
258 3 : .program_data_account = program_data_account,
259 3 : .upgrade_authority_address = upgrade_authority_address,
260 3 : .has_upgrade_authority_address = (uint)!!programdata_state->inner.program_data.has_upgrade_authority_address
261 3 : };
262 3 : return target_core_bpf;
263 3 : }
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, before any transaction execution. The program cache
349 : automatically invalidates all programs at the start of an epoch
350 : boundary, so we do not need to explicitly update the cache during the
351 : migration.
352 :
353 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L120-L218 */
354 : static int
355 : fd_directly_invoke_loader_v3_deploy_checks( fd_bank_t const * bank,
356 : fd_runtime_stack_t * runtime_stack,
357 : uchar const * elf,
358 3 : ulong elf_sz ) {
359 3 : fd_features_t const * features = &bank->f.features;
360 3 : ulong slot = bank->f.slot;
361 :
362 : /* ELF verification with deploy checks enabled */
363 3 : fd_prog_versions_t versions = fd_prog_versions( features, slot );
364 3 : fd_sbpf_loader_config_t loader_config = {
365 3 : .elf_deploy_checks = 1,
366 3 : .sbpf_min_version = versions.min_sbpf_version,
367 3 : .sbpf_max_version = versions.max_sbpf_version,
368 3 : };
369 3 : fd_sbpf_elf_info_t elf_info[1];
370 3 : if( FD_UNLIKELY( fd_sbpf_elf_peek( elf_info, elf, elf_sz, &loader_config )!=FD_SBPF_ELF_SUCCESS ) ) return 1;
371 :
372 : /* Setup program (includes calldests) */
373 3 : fd_sbpf_program_t * prog = fd_sbpf_program_new(
374 3 : runtime_stack->bpf_migration.progcache_validate.sbpf_footprint,
375 3 : elf_info,
376 3 : runtime_stack->bpf_migration.progcache_validate.rodata );
377 3 : if( FD_UNLIKELY( !prog ) ) return 1;
378 :
379 3 : fd_sbpf_syscalls_t _syscalls[ FD_SBPF_SYSCALLS_SLOT_CNT ];
380 3 : fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_join( fd_sbpf_syscalls_new( _syscalls ) );
381 3 : if( FD_UNLIKELY( !syscalls ) ) return 1;
382 3 : if( FD_UNLIKELY( fd_vm_syscall_register_slot( syscalls, slot, features, /* is_deploy */ 1 )!=FD_VM_SUCCESS ) ) return 1;
383 :
384 : /* fd_sbpf_program_load checks */
385 3 : if( FD_UNLIKELY( fd_sbpf_program_load(
386 3 : prog,
387 3 : elf,
388 3 : elf_sz,
389 3 : syscalls,
390 3 : &loader_config,
391 3 : runtime_stack->bpf_migration.progcache_validate.programdata,
392 3 : sizeof(runtime_stack->bpf_migration.progcache_validate.programdata) ) ) ) return 1;
393 :
394 : /* fd_vm_validate checks */
395 3 : fd_vm_t _vm[1];
396 3 : fd_vm_t * vm = fd_vm_join( fd_vm_new( _vm ) );
397 3 : if( FD_UNLIKELY( !vm ) ) return 1;
398 3 : vm = fd_vm_init( vm,
399 3 : NULL,
400 3 : 0UL,
401 3 : 0UL,
402 3 : prog->rodata,
403 3 : prog->rodata_sz,
404 3 : prog->text,
405 3 : prog->info.text_cnt,
406 3 : prog->info.text_off,
407 3 : prog->info.text_sz,
408 3 : prog->entry_pc,
409 3 : prog->calldests,
410 3 : elf_info->sbpf_version,
411 3 : syscalls,
412 3 : NULL,
413 3 : NULL,
414 3 : NULL,
415 3 : 0U,
416 3 : NULL,
417 3 : 0,
418 3 : FD_FEATURE_ACTIVE( slot, features, account_data_direct_mapping ),
419 3 : FD_FEATURE_ACTIVE( slot, features, syscall_parameter_address_restrictions ),
420 3 : FD_FEATURE_ACTIVE( slot, features, virtual_address_space_adjustments ),
421 3 : 0,
422 3 : 0UL );
423 3 : if( FD_UNLIKELY( !vm ) ) return 1;
424 3 : if( FD_UNLIKELY( fd_vm_validate( vm )!=FD_VM_SUCCESS ) ) return 1;
425 :
426 3 : return FD_EXECUTOR_INSTR_SUCCESS;
427 3 : }
428 :
429 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L51-L75 */
430 :
431 : static fd_tmp_account_t *
432 : source_buffer_new_checked( fd_tmp_account_t * acc,
433 : fd_accdb_t * accdb,
434 : fd_accdb_fork_id_t fork_id,
435 : fd_pubkey_t const * pubkey,
436 6 : fd_hash_t const * verified_build_hash ) {
437 :
438 6 : if( FD_UNLIKELY( !tmp_account_read( acc, accdb, fork_id, pubkey ) ) ) {
439 : /* CoreBpfMigrationError::AccountNotFound(*buffer_address) */
440 0 : return NULL;
441 0 : }
442 :
443 6 : if( FD_UNLIKELY( 0!=memcmp( acc->owner.uc, &fd_solana_bpf_loader_upgradeable_program_id, 32 ) ) ) {
444 : /* CoreBpfMigrationError::IncorrectOwner(*buffer_address) */
445 0 : return NULL;
446 0 : }
447 :
448 6 : if( acc->data_sz < BUFFER_METADATA_SIZE ) {
449 : /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
450 0 : return NULL;
451 0 : }
452 :
453 6 : fd_bpf_state_t state[1];
454 6 : if( FD_UNLIKELY( fd_bpf_state_decode( state, acc->data, BUFFER_METADATA_SIZE ) ) ) {
455 0 : return NULL;
456 0 : }
457 :
458 6 : if( FD_UNLIKELY( state->discriminant!=FD_BPF_STATE_BUFFER ) ) {
459 : /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
460 0 : return NULL;
461 0 : }
462 :
463 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L71 */
464 6 : if( verified_build_hash ) {
465 : /* Strip trailing zero-padding before hashing
466 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L63 */
467 0 : uchar const * data = (uchar const *)acc->data;
468 0 : ulong offset = BUFFER_METADATA_SIZE;
469 0 : ulong end_offset = acc->data_sz;
470 0 : while( end_offset>offset && data[end_offset-1]==0 ) end_offset--;
471 0 : uchar const * buffer_program_data = data + offset;
472 0 : ulong buffer_program_data_sz = end_offset - offset;
473 :
474 0 : fd_hash_t hash;
475 0 : fd_sha256_hash( buffer_program_data, buffer_program_data_sz, hash.uc );
476 0 : if( FD_UNLIKELY( 0!=memcmp( hash.uc, verified_build_hash->uc, FD_HASH_FOOTPRINT ) ) ) {
477 : /* CoreBpfMigrationError::BuildHashMismatch */
478 0 : return NULL;
479 0 : }
480 0 : }
481 :
482 6 : return acc;
483 6 : }
484 :
485 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L82-L95 */
486 :
487 : static fd_tmp_account_t *
488 : new_target_program_account( fd_tmp_account_t * acc,
489 : target_builtin_t const * target,
490 3 : fd_rent_t const * rent ) {
491 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L86-L88 */
492 3 : fd_bpf_state_t state = {
493 3 : .discriminant = FD_BPF_STATE_PROGRAM,
494 3 : .inner = {
495 3 : .program = {
496 3 : .programdata_address = target->program_data_address,
497 3 : }
498 3 : }
499 3 : };
500 :
501 3 : ulong state_sz = fd_bpf_state_size( &state );
502 3 : tmp_account_new( acc, state_sz );
503 3 : acc->lamports = fd_rent_exempt_minimum_balance( rent, SIZE_OF_PROGRAM );
504 3 : acc->executable = 1;
505 3 : memcpy( acc->owner.uc, fd_solana_bpf_loader_upgradeable_program_id.uc, sizeof(fd_pubkey_t) );
506 :
507 3 : ulong out_sz = 0UL;
508 3 : if( FD_UNLIKELY( fd_bpf_state_encode( &state, acc->data, state_sz, &out_sz ) ) ) {
509 0 : FD_LOG_ERR(( "fd_bpf_state_encode failed" ));
510 0 : }
511 :
512 3 : return acc;
513 3 : }
514 :
515 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L108-L153 */
516 : static fd_tmp_account_t *
517 : new_target_program_data_account( fd_tmp_account_t * acc,
518 : fd_tmp_account_t const * source,
519 : fd_pubkey_t const * upgrade_authority_address,
520 : fd_rent_t const * rent,
521 3 : ulong slot ) {
522 3 : ulong const buffer_metadata_sz = BUFFER_METADATA_SIZE;
523 :
524 3 : if( FD_UNLIKELY( source->data_sz < buffer_metadata_sz ) )
525 0 : return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
526 :
527 3 : fd_bpf_state_t state;
528 3 : if( FD_UNLIKELY( fd_bpf_state_decode( &state, source->data, buffer_metadata_sz ) ) ) {
529 0 : return NULL;
530 0 : }
531 :
532 3 : if( FD_UNLIKELY( state.discriminant!=FD_BPF_STATE_BUFFER ) )
533 0 : return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
534 :
535 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L118-L125 */
536 3 : if( upgrade_authority_address ) {
537 0 : if( FD_UNLIKELY( !state.inner.buffer.has_authority_address ||
538 0 : !fd_pubkey_eq( upgrade_authority_address, &state.inner.buffer.authority_address ) ) ) {
539 0 : return NULL; /* CoreBpfMigrationError::UpgradeAuthorityMismatch */
540 0 : }
541 0 : }
542 :
543 3 : void const * elf = (uchar const *)source->data + buffer_metadata_sz;
544 3 : ulong elf_sz = /* */source->data_sz - buffer_metadata_sz;
545 :
546 3 : ulong space = PROGRAMDATA_METADATA_SIZE + elf_sz;
547 3 : ulong lamports = fd_rent_exempt_minimum_balance( rent, space );
548 3 : fd_pubkey_t owner = fd_solana_bpf_loader_upgradeable_program_id;
549 :
550 3 : fd_bpf_state_t programdata_meta = {
551 3 : .discriminant = FD_BPF_STATE_PROGRAM_DATA,
552 3 : .inner = {
553 3 : .program_data = {
554 3 : .slot = slot,
555 3 : .has_upgrade_authority_address = !!upgrade_authority_address,
556 3 : .upgrade_authority_address = upgrade_authority_address ? *upgrade_authority_address : (fd_pubkey_t){{0}}
557 3 : }
558 3 : }
559 3 : };
560 :
561 3 : tmp_account_new( acc, space );
562 3 : acc->lamports = lamports;
563 3 : memcpy( acc->owner.uc, owner.uc, sizeof(fd_pubkey_t) );
564 3 : ulong out_sz = 0UL;
565 3 : if( FD_UNLIKELY( fd_bpf_state_encode( &programdata_meta, acc->data, PROGRAMDATA_METADATA_SIZE, &out_sz ) ) ) {
566 0 : FD_LOG_ERR(( "fd_bpf_state_encode failed" ));
567 0 : }
568 3 : fd_memcpy( (uchar *)acc->data+PROGRAMDATA_METADATA_SIZE, elf, elf_sz );
569 :
570 3 : return acc;
571 3 : }
572 :
573 : void
574 : migrate_builtin_to_core_bpf1( fd_core_bpf_migration_config_t const * config,
575 : fd_accdb_t * accdb,
576 : fd_bank_t * bank,
577 : fd_runtime_stack_t * runtime_stack,
578 : fd_pubkey_t const * builtin_program_id,
579 3 : fd_capture_ctx_t * capture_ctx ) {
580 :
581 3 : tmp_account_new( &runtime_stack->bpf_migration.program_account, 0UL );
582 :
583 3 : target_builtin_t target[1];
584 3 : if( FD_UNLIKELY( !target_builtin_new_checked(
585 3 : target,
586 3 : builtin_program_id,
587 3 : config->migration_target,
588 3 : FD_FEATURE_ACTIVE_BANK( bank, relax_programdata_account_check_migration ),
589 3 : accdb,
590 3 : bank->accdb_fork_id,
591 3 : runtime_stack ) ) )
592 0 : return;
593 :
594 3 : fd_memset( &runtime_stack->bpf_migration.source, 0, sizeof(runtime_stack->bpf_migration.source ) );
595 3 : fd_memset( &runtime_stack->bpf_migration.new_target_program, 0, sizeof(runtime_stack->bpf_migration.new_target_program ) );
596 3 : fd_memset( &runtime_stack->bpf_migration.new_target_program_data, 0, sizeof(runtime_stack->bpf_migration.new_target_program_data) );
597 3 : fd_memset( &runtime_stack->bpf_migration.empty, 0, sizeof(runtime_stack->bpf_migration.empty ) );
598 3 : fd_memset( &runtime_stack->bpf_migration.progcache_validate, 0, sizeof(runtime_stack->bpf_migration.progcache_validate ) );
599 :
600 3 : fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
601 3 : if( FD_UNLIKELY( !source_buffer_new_checked(
602 3 : source,
603 3 : accdb,
604 3 : bank->accdb_fork_id,
605 3 : config->source_buffer_address,
606 3 : config->verified_build_hash ) ) )
607 0 : return;
608 :
609 3 : fd_rent_t const * rent = &bank->f.rent;
610 3 : ulong const slot = bank->f.slot;
611 :
612 3 : fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration.new_target_program;
613 3 : if( FD_UNLIKELY( !new_target_program_account(
614 3 : new_target_program,
615 3 : target,
616 3 : rent ) ) )
617 0 : return;
618 3 : new_target_program->pubkey = *builtin_program_id;
619 :
620 3 : fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
621 3 : if( FD_UNLIKELY( !new_target_program_data_account(
622 3 : new_target_program_data,
623 3 : source,
624 3 : config->upgrade_authority_address,
625 3 : rent,
626 3 : slot ) ) )
627 0 : return;
628 3 : new_target_program_data->pubkey = target->program_data_address;
629 :
630 3 : ulong old_data_sz;
631 3 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
632 :
633 3 : ulong new_data_sz;
634 3 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return;
635 :
636 3 : FD_DCHECK_CRIT( new_target_program_data->data_sz>=PROGRAMDATA_METADATA_SIZE, "undersize account" );
637 : /* FIXME call fd_directly_invoke_loader_v3_deploy */
638 :
639 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L267-L281 */
640 3 : ulong lamports_to_burn;
641 3 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->lamports, source->lamports, &lamports_to_burn ) ) ) return;
642 3 : if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) ) return;
643 :
644 3 : ulong lamports_to_fund;
645 3 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->lamports, new_target_program_data->lamports, &lamports_to_fund ) ) ) return;
646 :
647 : /* Write back accounts */
648 3 : tmp_account_store( bank, accdb, new_target_program, capture_ctx, 0 );
649 3 : tmp_account_store( bank, accdb, new_target_program_data, capture_ctx, 1 );
650 3 : fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
651 3 : tmp_account_new( empty, 0UL );
652 3 : empty->pubkey = source->pubkey;
653 3 : tmp_account_store( bank, accdb, empty, capture_ctx, 0 );
654 :
655 : /* FIXME "remove the built-in program from the bank's list of builtins" */
656 : /* FIXME "update account data size delta" */
657 3 : }
658 :
659 : /* Mimics migrate_builtin_to_core_bpf().
660 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#215-303 */
661 : void
662 : fd_migrate_builtin_to_core_bpf( fd_bank_t * bank,
663 : fd_accdb_t * accdb,
664 : fd_runtime_stack_t * runtime_stack,
665 : fd_core_bpf_migration_config_t const * config,
666 3 : fd_capture_ctx_t * capture_ctx ) {
667 3 : migrate_builtin_to_core_bpf1( config, accdb, bank, runtime_stack, config->builtin_program_id, capture_ctx );
668 3 : }
669 :
670 : /* Mimics upgrade_core_bpf_program().
671 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L319-L377 */
672 : void
673 : fd_upgrade_core_bpf_program( fd_bank_t * bank,
674 : fd_accdb_t * accdb,
675 : fd_runtime_stack_t * runtime_stack,
676 : fd_pubkey_t const * builtin_program_id,
677 : fd_pubkey_t const * source_buffer_address,
678 3 : fd_capture_ctx_t * capture_ctx ) {
679 3 : fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
680 :
681 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L327 */
682 3 : target_core_bpf_t target[1];
683 3 : if( FD_UNLIKELY( !target_core_bpf_new_checked( target, builtin_program_id, accdb, bank->accdb_fork_id, runtime_stack ) ) ) {
684 0 : return;
685 0 : }
686 :
687 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L328 */
688 3 : fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
689 3 : if( FD_UNLIKELY( !source_buffer_new_checked( source, accdb, bank->accdb_fork_id, source_buffer_address, NULL ) ) ) {
690 0 : return;
691 0 : }
692 :
693 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L118-L125 */
694 3 : if( target->has_upgrade_authority_address ) {
695 3 : fd_bpf_state_t buffer_state[1];
696 3 : if( FD_UNLIKELY( fd_bpf_state_decode( buffer_state, source->data, BUFFER_METADATA_SIZE ) ||
697 3 : buffer_state->discriminant!=FD_BPF_STATE_BUFFER ||
698 3 : !buffer_state->inner.buffer.has_authority_address ||
699 3 : !fd_pubkey_eq( &target->upgrade_authority_address, &buffer_state->inner.buffer.authority_address ) ) ) {
700 : /* CoreBpfMigrationError::UpgradeAuthorityMismatch */
701 0 : FD_LOG_WARNING(( "core-BPF program upgrade aborted at slot %lu: source buffer authority does not match the target program's upgrade authority",
702 0 : bank->f.slot ));
703 0 : return;
704 0 : }
705 3 : }
706 :
707 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L331-L332 */
708 3 : fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
709 3 : fd_pubkey_t program_data_address = get_program_data_address( builtin_program_id );
710 :
711 3 : ulong program_data_len = source->data_sz - BUFFER_METADATA_SIZE;
712 3 : ulong new_account_size = PROGRAMDATA_METADATA_SIZE + program_data_len;
713 :
714 3 : tmp_account_new( new_target_program_data, new_account_size );
715 3 : new_target_program_data->pubkey = program_data_address;
716 :
717 3 : fd_rent_t const * rent = &bank->f.rent;
718 3 : new_target_program_data->lamports = fd_rent_exempt_minimum_balance( rent, new_account_size );
719 3 : new_target_program_data->executable = 0;
720 3 : fd_memcpy( new_target_program_data->owner.uc, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) );
721 :
722 3 : fd_bpf_state_t programdata_state[1] = {{
723 3 : .discriminant = FD_BPF_STATE_PROGRAM_DATA,
724 3 : .inner = { .program_data = {
725 3 : .slot = bank->f.slot,
726 3 : .upgrade_authority_address = target->upgrade_authority_address,
727 3 : .has_upgrade_authority_address = target->has_upgrade_authority_address
728 3 : }}
729 3 : }};
730 :
731 3 : ulong out_sz = 0UL;
732 3 : if( FD_UNLIKELY( fd_bpf_state_encode( programdata_state, new_target_program_data->data, PROGRAMDATA_METADATA_SIZE, &out_sz ) ) ) {
733 0 : return;
734 0 : }
735 :
736 3 : fd_memcpy( new_target_program_data->data + PROGRAMDATA_METADATA_SIZE,
737 3 : source->data + BUFFER_METADATA_SIZE,
738 3 : program_data_len );
739 :
740 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.4/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L339-L346 */
741 3 : ulong old_data_sz;
742 3 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
743 3 : ulong new_data_sz = new_target_program_data->data_sz;
744 :
745 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.4/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L349-L355 */
746 3 : uchar const * elf = new_target_program_data->data + PROGRAMDATA_METADATA_SIZE;
747 3 : ulong elf_sz = program_data_len;
748 3 : if( FD_UNLIKELY( fd_directly_invoke_loader_v3_deploy_checks( bank, runtime_stack, elf, elf_sz ) ) ) return;
749 :
750 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L359-L364 */
751 3 : ulong lamports_to_burn;
752 3 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->lamports, source->lamports, &lamports_to_burn ) ) ) return;
753 :
754 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L366-L371 */
755 3 : fd_pubkey_t source_addr = source->pubkey;
756 3 : tmp_account_store( bank, accdb, new_target_program_data, capture_ctx, 1 );
757 :
758 3 : fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
759 3 : tmp_account_new( empty, 0UL );
760 3 : empty->pubkey = source_addr;
761 3 : tmp_account_store( bank, accdb, empty, capture_ctx, 0 );
762 :
763 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L374 */
764 : /* FIXME "update account data size delta" */
765 3 : (void)old_data_sz;
766 3 : (void)new_data_sz;
767 :
768 3 : fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
769 3 : }
770 :
771 : /* Mimics upgrade_loader_v2_program_with_loader_v3_program().
772 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L402-L474 */
773 : void
774 : fd_upgrade_loader_v2_program_with_loader_v3_program( fd_bank_t * bank,
775 : fd_accdb_t * accdb,
776 : fd_runtime_stack_t * runtime_stack,
777 : fd_pubkey_t const * loader_v2_program_address,
778 : fd_pubkey_t const * source_buffer_address,
779 : int allow_prefunded,
780 0 : fd_capture_ctx_t * capture_ctx ) {
781 0 : fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
782 :
783 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L411-L412 */
784 0 : target_builtin_t target[1];
785 0 : if( FD_UNLIKELY( !target_bpf_v2_new_checked(
786 0 : target,
787 0 : loader_v2_program_address,
788 0 : allow_prefunded,
789 0 : accdb,
790 0 : bank->accdb_fork_id,
791 0 : runtime_stack ) ) )
792 0 : return;
793 :
794 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L413 */
795 0 : fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
796 0 : if( FD_UNLIKELY( !source_buffer_new_checked( source, accdb, bank->accdb_fork_id, source_buffer_address, NULL ) ) )
797 0 : return;
798 :
799 0 : fd_rent_t const * rent = &bank->f.rent;
800 0 : ulong slot = bank->f.slot;
801 :
802 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L416-L417 */
803 0 : fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration.new_target_program;
804 0 : if( FD_UNLIKELY( !new_target_program_account( new_target_program, target, rent ) ) )
805 0 : return;
806 0 : new_target_program->pubkey = *loader_v2_program_address;
807 :
808 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L419-L421 */
809 0 : fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
810 0 : if( FD_UNLIKELY( !new_target_program_data_account( new_target_program_data, source, NULL, rent, slot ) ) ) {
811 0 : return;
812 0 : }
813 0 : new_target_program_data->pubkey = target->program_data_address;
814 :
815 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L427-L435 */
816 0 : ulong old_data_sz;
817 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
818 :
819 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L432-L435 */
820 0 : ulong new_data_sz;
821 0 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return;
822 :
823 0 : if( FD_UNLIKELY( new_target_program_data->data_sz<PROGRAMDATA_METADATA_SIZE ) ) {
824 0 : FD_LOG_CRIT(( "invariant violation: new target programdata too small" ));
825 0 : }
826 :
827 : /* Agave calls directly_invoke_loader_v3_deploy to deploy the new
828 : program to the program cache. We don't do that, but instead we
829 : perform the same checks as directly_invoke_loader_v3_deploy
830 : without modifying the program cache. We need to do the checks
831 : at this point so that we can fail the upgrade if the ELF is
832 : invalid.
833 :
834 : This is safe because the bpf migration code runs at the epoch
835 : boundary, before any transaction execution. The program cache
836 : automatically invalidates all programs at the start of an epoch
837 : boundary, so we do not need to explicitly update the cache during the
838 : migration.
839 :
840 : https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L437-L443*/
841 0 : uchar const * elf = (uchar const *)new_target_program_data->data + PROGRAMDATA_METADATA_SIZE;
842 0 : ulong elf_sz = new_target_program_data->data_sz - PROGRAMDATA_METADATA_SIZE;
843 0 : if( FD_UNLIKELY( fd_directly_invoke_loader_v3_deploy_checks( bank, runtime_stack, elf, elf_sz ) ) ) return;
844 :
845 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L451-L459 */
846 0 : ulong lamports_to_burn;
847 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->lamports, source->lamports, &lamports_to_burn ) ) ) return;
848 0 : if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) ) return;
849 :
850 0 : ulong lamports_to_fund;
851 0 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->lamports, new_target_program_data->lamports, &lamports_to_fund ) ) ) return;
852 :
853 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L462-L468 */
854 0 : tmp_account_store( bank, accdb, new_target_program, capture_ctx, 0 );
855 0 : tmp_account_store( bank, accdb, new_target_program_data, capture_ctx, 1 );
856 :
857 0 : fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
858 0 : tmp_account_new( empty, 0UL );
859 0 : empty->pubkey = source->pubkey;
860 0 : tmp_account_store( bank, accdb, empty, capture_ctx, 0 );
861 :
862 : /* NB: Agave updates "delta_off_chain", using these two fields,
863 : which is not consensus-critical (only used for Agave stats)
864 : so we don't update this in our migration code or store this in
865 : our bank. */
866 0 : (void)old_data_sz;
867 0 : (void)new_data_sz;
868 :
869 0 : fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
870 0 : }
|