Line data Source code
1 : #include "sysvar/fd_sysvar_rent.h"
2 : #include "program/fd_bpf_loader_program.h"
3 : #include "program/fd_builtin_programs.h"
4 : #include "program/fd_program_util.h"
5 : #include "fd_runtime_stack.h"
6 : #include "fd_pubkey_utils.h"
7 : #include "fd_system_ids.h"
8 : #include "fd_hashes.h"
9 : #include "../accdb/fd_accdb_sync.h"
10 : #include "../../ballet/sha256/fd_sha256.h"
11 : #include <assert.h>
12 :
13 : static fd_pubkey_t
14 2 : get_program_data_address( fd_pubkey_t const * program_addr ) {
15 2 : uchar const * seed = program_addr->uc;
16 2 : ulong seed_sz = 32UL;
17 2 : fd_pubkey_t out;
18 2 : uint custom_err;
19 2 : uchar out_bump_seed;
20 2 : int err = fd_pubkey_find_program_address( &fd_solana_bpf_loader_upgradeable_program_id, 1UL, &seed, &seed_sz, &out, &out_bump_seed, &custom_err );
21 2 : if( FD_UNLIKELY( err ) ) {
22 : /* https://github.com/anza-xyz/solana-sdk/blob/address%40v2.1.0/address/src/syscalls.rs#L277-L279 */
23 0 : FD_LOG_ERR(( "Unable to find a viable program address bump seed" ));
24 0 : }
25 2 : return out;
26 2 : }
27 :
28 : fd_tmp_account_t *
29 : tmp_account_new( fd_tmp_account_t * acc,
30 0 : ulong acc_sz ) {
31 0 : acc->data_sz = acc_sz;
32 0 : fd_memset( acc->data, 0, acc_sz );
33 0 : return acc;
34 0 : }
35 :
36 : fd_tmp_account_t *
37 : tmp_account_read( fd_tmp_account_t * acc,
38 : fd_accdb_user_t * accdb,
39 : fd_funk_txn_xid_t const * xid,
40 2 : fd_pubkey_t const * addr ) {
41 2 : fd_accdb_ro_t ro[1];
42 2 : if( FD_LIKELY( !fd_accdb_open_ro( accdb, ro, xid, addr ) ) ) return NULL;
43 0 : tmp_account_new( acc, fd_accdb_ref_data_sz( ro ) );
44 0 : acc->meta = *ro->meta;
45 0 : acc->addr = *addr;
46 0 : fd_memcpy( acc->data, fd_accdb_ref_data_const( ro ), fd_accdb_ref_data_sz( ro ) );
47 0 : acc->data_sz = fd_accdb_ref_data_sz( ro );
48 0 : fd_accdb_close_ro( accdb, ro );
49 0 : return acc;
50 2 : }
51 :
52 : void
53 : tmp_account_store( fd_tmp_account_t * acc,
54 : fd_accdb_user_t * accdb,
55 : fd_funk_txn_xid_t const * xid,
56 : fd_bank_t * bank,
57 0 : fd_capture_ctx_t * capture_ctx ) {
58 0 : if( FD_UNLIKELY( fd_pubkey_eq( &acc->addr, &fd_solana_system_program_id ) ) ) {
59 0 : FD_LOG_ERR(( "Attempted to write to the system program account" ));
60 0 : }
61 :
62 0 : fd_accdb_rw_t rw[1];
63 0 : fd_accdb_open_rw( accdb, rw, xid, &acc->addr, acc->data_sz, FD_ACCDB_FLAG_CREATE );
64 0 : fd_lthash_value_t prev_hash[1];
65 0 : fd_hashes_account_lthash( &acc->addr, rw->meta, fd_accdb_ref_data_const( rw->ro ), prev_hash );
66 :
67 0 : fd_accdb_ref_exec_bit_set( rw, acc->meta.executable );
68 0 : fd_accdb_ref_owner_set ( rw, acc->meta.owner );
69 0 : fd_accdb_ref_lamports_set( rw, acc->meta.lamports );
70 0 : fd_accdb_ref_data_set ( accdb, rw, acc->data, acc->data_sz );
71 :
72 0 : fd_hashes_update_lthash( &acc->addr, rw->meta, prev_hash, bank, capture_ctx );
73 0 : fd_accdb_close_rw( accdb, rw );
74 0 : }
75 :
76 : /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_core_bpf.rs#L12 */
77 :
78 : struct target_core_bpf {
79 : fd_pubkey_t program_address;
80 : fd_tmp_account_t * program_data_account;
81 : fd_pubkey_t upgrade_authority_address;
82 : uint has_upgrade_authority_address : 1;
83 : };
84 :
85 : typedef struct target_core_bpf target_core_bpf_t;
86 :
87 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L19 */
88 :
89 : struct target_builtin {
90 : fd_tmp_account_t * program_account;
91 : fd_pubkey_t program_data_address;
92 : ulong program_data_account_lamports;
93 : };
94 :
95 : typedef struct target_builtin target_builtin_t;
96 :
97 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L25-L91 */
98 :
99 : target_builtin_t *
100 : target_builtin_new_checked( target_builtin_t * target_builtin,
101 : fd_pubkey_t const * program_address,
102 : int migration_target,
103 : int relax_programdata_account_check_migration,
104 : fd_accdb_user_t * accdb,
105 : fd_funk_txn_xid_t const * xid,
106 2 : fd_runtime_stack_t * runtime_stack ) {
107 :
108 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L31-L53 */
109 :
110 2 : fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
111 2 : switch( migration_target ) {
112 0 : case FD_CORE_BPF_MIGRATION_TARGET_BUILTIN:
113 0 : if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, xid, program_address ) ) ) {
114 : /* CoreBpfMigrationError::AccountNotFound(*program_address) */
115 0 : return NULL;
116 0 : }
117 0 : if( FD_UNLIKELY( 0!=memcmp( program_account->meta.owner, &fd_solana_native_loader_id, 32 ) ) ) {
118 : /* CoreBpfMigrationError::IncorrectOwner(*program_address) */
119 0 : return NULL;
120 0 : }
121 0 : break;
122 2 : case FD_CORE_BPF_MIGRATION_TARGET_STATELESS: {
123 : /* Program account should not exist */
124 2 : fd_accdb_ro_t ro[1];
125 2 : int progdata_exists = !!fd_accdb_open_ro( accdb, ro, xid, program_address );
126 2 : if( progdata_exists ) {
127 : /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
128 0 : fd_accdb_close_ro( accdb, ro );
129 0 : return NULL;
130 0 : }
131 2 : break;
132 2 : }
133 2 : default:
134 0 : FD_LOG_ERR(( "invalid migration_target %d", migration_target ));
135 2 : }
136 :
137 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L55 */
138 :
139 2 : fd_pubkey_t program_data_address = get_program_data_address( program_address );
140 :
141 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L57-L82 */
142 :
143 2 : ulong program_data_account_lamports = 0UL;
144 2 : do {
145 : /* Program data account should not exist */
146 2 : fd_accdb_ro_t ro[1];
147 2 : int progdata_exists = !!fd_accdb_open_ro( accdb, ro, xid, &program_data_address );
148 :
149 : /* SIMD-0444: relax_programdata_account_check_migration
150 : https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L57-L70 */
151 2 : if( relax_programdata_account_check_migration ) {
152 : /* The program data account should not exist, but a system
153 : account with funded lamports is acceptable. */
154 0 : if( FD_UNLIKELY( progdata_exists ) ) {
155 0 : if( FD_UNLIKELY( 0!=memcmp( fd_accdb_ref_owner( ro ), &fd_solana_system_program_id, sizeof(fd_pubkey_t) ) ) ) {
156 : /* CoreBpfMigrationError::ProgramHasDataAccount(
157 : *program_address) */
158 0 : fd_accdb_close_ro( accdb, ro );
159 0 : return NULL;
160 0 : } else {
161 0 : program_data_account_lamports = fd_accdb_ref_lamports( ro );
162 0 : fd_accdb_close_ro( accdb, ro );
163 0 : }
164 0 : }
165 2 : } else {
166 : /* If relax_programdata_account_check_migration is not enabled,
167 : we do not allow the program data account to exist at all. */
168 2 : if( FD_UNLIKELY( progdata_exists ) ) {
169 : /* CoreBpfMigrationError::AccountAlreadyExists(*program_address) */
170 0 : fd_accdb_close_ro( accdb, ro );
171 0 : return NULL;
172 0 : }
173 2 : }
174 2 : } while(0);
175 :
176 : /* https://github.com/anza-xyz/agave/blob/v3.0.2/runtime/src/bank/builtins/core_bpf_migration/target_builtin.rs#L63-L67 */
177 :
178 2 : *target_builtin = (target_builtin_t) {
179 2 : .program_account = program_account,
180 2 : .program_data_address = program_data_address,
181 2 : .program_data_account_lamports = program_data_account_lamports
182 2 : };
183 2 : return target_builtin;
184 2 : }
185 :
186 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/target_core_bpf.rs#L26-L93 */
187 : static target_core_bpf_t *
188 : target_core_bpf_new_checked( target_core_bpf_t * target_core_bpf,
189 : fd_pubkey_t const * program_address,
190 : fd_accdb_user_t * accdb,
191 : fd_funk_txn_xid_t const * xid,
192 0 : fd_runtime_stack_t * runtime_stack ) {
193 0 : fd_pubkey_t program_data_address = get_program_data_address( program_address );
194 :
195 : /* The program account should exist */
196 0 : fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account;
197 0 : if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, xid, program_address ) ) ) {
198 0 : return NULL;
199 0 : }
200 :
201 : /* The program account should be owned by the upgradeable loader */
202 0 : if( FD_UNLIKELY( 0!=memcmp( program_account->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) ) ) ) {
203 0 : return NULL;
204 0 : }
205 :
206 : /* The program account should be executable */
207 0 : if( FD_UNLIKELY( !program_account->meta.executable ) ) {
208 0 : return NULL;
209 0 : }
210 :
211 : /* Decode and validate program account state */
212 0 : fd_bpf_upgradeable_loader_state_t program_state[1];
213 0 : if( FD_UNLIKELY( FD_EXECUTOR_INSTR_SUCCESS!=fd_bpf_loader_program_get_state( &program_account->meta, program_state ) ) ) {
214 0 : return NULL;
215 0 : }
216 0 : if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_program( program_state ) ) ) {
217 0 : return NULL;
218 0 : }
219 0 : if( FD_UNLIKELY( 0!=memcmp( &program_state->inner.program.programdata_address, &program_data_address, sizeof(fd_pubkey_t) ) ) ) {
220 0 : return NULL;
221 0 : }
222 :
223 : /* The program data account should exist */
224 0 : fd_tmp_account_t * program_data_account = &runtime_stack->bpf_migration.new_target_program;
225 0 : if( FD_UNLIKELY( !tmp_account_read( program_data_account, accdb, xid, &program_data_address ) ) ) {
226 0 : return NULL;
227 0 : }
228 :
229 : /* The program data account should be owned by the upgradeable loader */
230 0 : if( FD_UNLIKELY( 0!=memcmp( program_data_account->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) ) ) ) {
231 0 : return NULL;
232 0 : }
233 :
234 : /* Decode and validate program data account state */
235 0 : fd_bpf_upgradeable_loader_state_t programdata_state[1];
236 0 : if( FD_UNLIKELY( FD_EXECUTOR_INSTR_SUCCESS!=fd_bpf_loader_program_get_state( &program_data_account->meta, programdata_state ) ) ) {
237 0 : return NULL;
238 0 : }
239 0 : if( FD_UNLIKELY( !fd_bpf_upgradeable_loader_state_is_program_data( programdata_state ) ) ) {
240 0 : return NULL;
241 0 : }
242 :
243 : /* Extract upgrade authority from program data state */
244 0 : fd_pubkey_t upgrade_authority_address;
245 0 : if( programdata_state->inner.program_data.has_upgrade_authority_address ) {
246 0 : upgrade_authority_address = programdata_state->inner.program_data.upgrade_authority_address;
247 0 : } else {
248 0 : fd_memset( &upgrade_authority_address, 0, sizeof(fd_pubkey_t) );
249 0 : }
250 :
251 0 : *target_core_bpf = (target_core_bpf_t) {
252 0 : .program_address = *program_address,
253 0 : .program_data_account = program_data_account,
254 0 : .upgrade_authority_address = upgrade_authority_address,
255 0 : .has_upgrade_authority_address = (uint)!!programdata_state->inner.program_data.has_upgrade_authority_address
256 0 : };
257 0 : return target_core_bpf;
258 0 : }
259 :
260 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L51-L75 */
261 :
262 : static fd_tmp_account_t *
263 : source_buffer_new_checked( fd_tmp_account_t * acc,
264 : fd_accdb_user_t * accdb,
265 : fd_funk_txn_xid_t const * xid,
266 : fd_pubkey_t const * pubkey,
267 2 : fd_hash_t const * verified_build_hash ) {
268 :
269 2 : if( FD_UNLIKELY( !tmp_account_read( acc, accdb, xid, pubkey ) ) ) {
270 : /* CoreBpfMigrationError::AccountNotFound(*buffer_address) */
271 2 : return NULL;
272 2 : }
273 :
274 0 : if( FD_UNLIKELY( 0!=memcmp( acc->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, 32 ) ) ) {
275 : /* CoreBpfMigrationError::IncorrectOwner(*buffer_address) */
276 0 : return NULL;
277 0 : }
278 :
279 0 : if( acc->data_sz < BUFFER_METADATA_SIZE ) {
280 : /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
281 0 : return NULL;
282 0 : }
283 :
284 0 : fd_bpf_upgradeable_loader_state_t state[1];
285 0 : if( FD_UNLIKELY( !fd_bincode_decode_static(
286 0 : bpf_upgradeable_loader_state, state,
287 0 : acc->data, BUFFER_METADATA_SIZE ) ) ) {
288 0 : return NULL;
289 0 : }
290 :
291 0 : if( FD_UNLIKELY( state->discriminant!=fd_bpf_upgradeable_loader_state_enum_buffer ) ) {
292 : /* CoreBpfMigrationError::InvalidBufferAccount(*buffer_address) */
293 0 : return NULL;
294 0 : }
295 :
296 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L71 */
297 0 : if( verified_build_hash ) {
298 : /* Strip trailing zero-padding before hashing
299 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L61-L63 */
300 0 : uchar const * data = (uchar const *)acc->data;
301 0 : ulong offset = BUFFER_METADATA_SIZE;
302 0 : ulong end_offset = acc->data_sz;
303 0 : while( end_offset>offset && data[end_offset-1]==0 ) end_offset--;
304 0 : uchar const * buffer_program_data = data + offset;
305 0 : ulong buffer_program_data_sz = end_offset - offset;
306 :
307 0 : fd_hash_t hash;
308 0 : fd_sha256_hash( buffer_program_data, buffer_program_data_sz, hash.uc );
309 0 : if( FD_UNLIKELY( 0!=memcmp( hash.uc, verified_build_hash->uc, FD_HASH_FOOTPRINT ) ) ) {
310 : /* CoreBpfMigrationError::BuildHashMismatch */
311 0 : return NULL;
312 0 : }
313 0 : }
314 :
315 0 : return acc;
316 0 : }
317 :
318 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L82-L95 */
319 :
320 : static fd_tmp_account_t *
321 : new_target_program_account( fd_tmp_account_t * acc,
322 : target_builtin_t const * target,
323 0 : fd_rent_t const * rent ) {
324 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L86-L88 */
325 0 : fd_bpf_upgradeable_loader_state_t state = {
326 0 : .discriminant = fd_bpf_upgradeable_loader_state_enum_program,
327 0 : .inner = {
328 0 : .program = {
329 0 : .programdata_address = target->program_data_address,
330 0 : }
331 0 : }
332 0 : };
333 :
334 0 : ulong state_sz = fd_bpf_upgradeable_loader_state_size( &state );
335 0 : tmp_account_new( acc, state_sz );
336 0 : acc->meta.lamports = fd_rent_exempt_minimum_balance( rent, SIZE_OF_PROGRAM );
337 0 : acc->meta.executable = 1;
338 0 : memcpy( acc->meta.owner, fd_solana_bpf_loader_upgradeable_program_id.uc, sizeof(fd_pubkey_t) );
339 :
340 0 : fd_bincode_encode_ctx_t ctx = { .data=acc->data, .dataend=(uchar *)acc->data+state_sz };
341 0 : if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_encode( &state, &ctx )!=FD_BINCODE_SUCCESS ) ) {
342 0 : FD_LOG_ERR(( "fd_bpf_upgradeable_loader_state_encode failed" ));
343 0 : }
344 :
345 0 : return acc;
346 0 : }
347 :
348 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L108-L153 */
349 : static fd_tmp_account_t *
350 : new_target_program_data_account( fd_tmp_account_t * acc,
351 : fd_tmp_account_t const * source,
352 : fd_pubkey_t const * upgrade_authority_address,
353 : fd_rent_t const * rent,
354 0 : ulong slot ) {
355 0 : ulong const buffer_metadata_sz = BUFFER_METADATA_SIZE;
356 :
357 0 : if( FD_UNLIKELY( source->data_sz < buffer_metadata_sz ) )
358 0 : return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
359 :
360 0 : fd_bpf_upgradeable_loader_state_t state;
361 0 : if( !fd_bincode_decode_static(
362 0 : bpf_upgradeable_loader_state,
363 0 : &state,
364 0 : source->data,
365 0 : buffer_metadata_sz ) )
366 0 : return NULL;
367 :
368 0 : if( FD_UNLIKELY( state.discriminant!=fd_bpf_upgradeable_loader_state_enum_buffer ) )
369 0 : return NULL; /* CoreBpfMigrationError::InvalidBufferAccount */
370 :
371 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L118-L125 */
372 0 : if( upgrade_authority_address ) {
373 0 : if( FD_UNLIKELY( !state.inner.buffer.has_authority_address ||
374 0 : !fd_pubkey_eq( upgrade_authority_address, &state.inner.buffer.authority_address ) ) ) {
375 0 : return NULL; /* CoreBpfMigrationError::UpgradeAuthorityMismatch */
376 0 : }
377 0 : }
378 :
379 0 : void const * elf = (uchar const *)source->data + buffer_metadata_sz;
380 0 : ulong elf_sz = /* */source->data_sz - buffer_metadata_sz;
381 :
382 0 : ulong space = PROGRAMDATA_METADATA_SIZE + elf_sz;
383 0 : ulong lamports = fd_rent_exempt_minimum_balance( rent, space );
384 0 : fd_pubkey_t owner = fd_solana_bpf_loader_upgradeable_program_id;
385 :
386 0 : fd_bpf_upgradeable_loader_state_t programdata_meta = {
387 0 : .discriminant = fd_bpf_upgradeable_loader_state_enum_program_data,
388 0 : .inner = {
389 0 : .program_data = {
390 0 : .slot = slot,
391 0 : .has_upgrade_authority_address = !!upgrade_authority_address,
392 0 : .upgrade_authority_address = upgrade_authority_address ? *upgrade_authority_address : (fd_pubkey_t){{0}}
393 0 : }
394 0 : }
395 0 : };
396 :
397 0 : tmp_account_new( acc, space );
398 0 : acc->meta.lamports = lamports;
399 0 : memcpy( acc->meta.owner, owner.uc, sizeof(fd_pubkey_t) );
400 0 : fd_bincode_encode_ctx_t ctx = { .data=acc->data, .dataend=(uchar *)acc->data+PROGRAMDATA_METADATA_SIZE };
401 0 : if( FD_UNLIKELY( fd_bpf_upgradeable_loader_state_encode( &programdata_meta, &ctx )!=FD_BINCODE_SUCCESS ) ) {
402 0 : FD_LOG_ERR(( "fd_bpf_upgradeable_loader_state_encode failed" ));
403 0 : }
404 0 : fd_memcpy( (uchar *)acc->data+PROGRAMDATA_METADATA_SIZE, elf, elf_sz );
405 :
406 0 : return acc;
407 0 : }
408 :
409 : /* Mimics update_captalization()
410 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L471-L490 */
411 : static inline int
412 : fd_update_capitalization( fd_bank_t * bank,
413 : ulong lamports_to_burn,
414 0 : ulong lamports_to_fund ) {
415 0 : if( lamports_to_burn > lamports_to_fund ) {
416 0 : ulong diff;
417 0 : int err = fd_ulong_checked_sub( lamports_to_burn, lamports_to_fund, &diff );
418 0 : if( FD_UNLIKELY( err ) ) return err;
419 :
420 0 : ulong capitalization = fd_bank_capitalization_get( bank );
421 0 : ulong new_capitalization;
422 0 : err = fd_ulong_checked_sub( capitalization, diff, &new_capitalization );
423 0 : if( FD_UNLIKELY( err ) ) return err;
424 :
425 0 : fd_bank_capitalization_set( bank, new_capitalization );
426 0 : } else if( lamports_to_fund > lamports_to_burn ) {
427 0 : ulong diff;
428 0 : int err = fd_ulong_checked_sub( lamports_to_fund, lamports_to_burn, &diff );
429 0 : if( FD_UNLIKELY( err ) ) return err;
430 :
431 0 : ulong capitalization = fd_bank_capitalization_get( bank );
432 0 : ulong new_capitalization;
433 0 : err = fd_ulong_checked_add( capitalization, diff, &new_capitalization );
434 0 : if( FD_UNLIKELY( err ) ) return err;
435 :
436 0 : fd_bank_capitalization_set( bank, new_capitalization );
437 0 : }
438 :
439 0 : return FD_EXECUTOR_INSTR_SUCCESS;
440 0 : }
441 :
442 : void
443 : migrate_builtin_to_core_bpf1( fd_core_bpf_migration_config_t const * config,
444 : fd_accdb_user_t * accdb,
445 : fd_funk_txn_xid_t const * xid,
446 : fd_bank_t * bank,
447 : fd_runtime_stack_t * runtime_stack,
448 : fd_pubkey_t const * builtin_program_id,
449 2 : fd_capture_ctx_t * capture_ctx ) {
450 2 : target_builtin_t target[1];
451 2 : if( FD_UNLIKELY( !target_builtin_new_checked(
452 2 : target,
453 2 : builtin_program_id,
454 2 : config->migration_target,
455 2 : FD_FEATURE_ACTIVE_BANK( bank, relax_programdata_account_check_migration ),
456 2 : accdb,
457 2 : xid,
458 2 : runtime_stack ) ) )
459 0 : return;
460 :
461 2 : fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
462 2 : if( FD_UNLIKELY( !source_buffer_new_checked(
463 2 : source,
464 2 : accdb,
465 2 : xid,
466 2 : config->source_buffer_address,
467 2 : config->verified_build_hash ) ) )
468 2 : return;
469 :
470 0 : fd_rent_t const * rent = fd_bank_rent_query( bank );
471 0 : ulong const slot = fd_bank_slot_get ( bank );
472 :
473 0 : fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration.new_target_program;
474 0 : if( FD_UNLIKELY( !new_target_program_account(
475 0 : new_target_program,
476 0 : target,
477 0 : rent ) ) )
478 0 : return;
479 0 : new_target_program->addr = *builtin_program_id;
480 :
481 0 : fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
482 0 : if( FD_UNLIKELY( !new_target_program_data_account(
483 0 : new_target_program_data,
484 0 : source,
485 0 : config->upgrade_authority_address,
486 0 : rent,
487 0 : slot ) ) )
488 0 : return;
489 0 : new_target_program_data->addr = target->program_data_address;
490 :
491 0 : ulong old_data_sz;
492 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
493 :
494 0 : ulong new_data_sz;
495 0 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return;
496 :
497 0 : assert( new_target_program_data->data_sz>=PROGRAMDATA_METADATA_SIZE );
498 : /* FIXME call fd_directly_invoke_loader_v3_deploy */
499 :
500 : /* https://github.com/anza-xyz/agave/blob/v3.1.8/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L267-L281 */
501 0 : ulong lamports_to_burn;
502 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->meta.lamports, source->meta.lamports, &lamports_to_burn ) ) ) return;
503 0 : if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) ) return;
504 :
505 0 : ulong lamports_to_fund;
506 0 : if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->meta.lamports, new_target_program_data->meta.lamports, &lamports_to_fund ) ) ) return;
507 :
508 : /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L286-L297 */
509 0 : if( FD_UNLIKELY( fd_update_capitalization( bank, lamports_to_burn, lamports_to_fund ) ) ) {
510 0 : FD_LOG_ERR(( "Capitalization overflow while migrating builtin program to core BPF" ));
511 0 : }
512 :
513 : /* Write back accounts */
514 0 : tmp_account_store( new_target_program, accdb, xid, bank, capture_ctx );
515 0 : tmp_account_store( new_target_program_data, accdb, xid, bank, capture_ctx );
516 0 : fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
517 0 : tmp_account_new( empty, 0UL );
518 0 : empty->addr = source->addr;
519 0 : tmp_account_store( empty, accdb, xid, bank, capture_ctx );
520 :
521 : /* FIXME "remove the built-in program from the bank's list of builtins" */
522 : /* FIXME "update account data size delta" */
523 0 : }
524 :
525 : /* Mimics migrate_builtin_to_core_bpf().
526 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#215-303 */
527 : void
528 : fd_migrate_builtin_to_core_bpf( fd_bank_t * bank,
529 : fd_accdb_user_t * accdb,
530 : fd_funk_txn_xid_t const * xid,
531 : fd_runtime_stack_t * runtime_stack,
532 : fd_core_bpf_migration_config_t const * config,
533 2 : fd_capture_ctx_t * capture_ctx ) {
534 2 : migrate_builtin_to_core_bpf1( config, accdb, xid, bank, runtime_stack, config->builtin_program_id, capture_ctx );
535 2 : }
536 :
537 : /* Mimics upgrade_core_bpf_program().
538 : https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L319-L377 */
539 : void
540 : fd_upgrade_core_bpf_program( fd_bank_t * bank,
541 : fd_accdb_user_t * accdb,
542 : fd_funk_txn_xid_t const * xid,
543 : fd_runtime_stack_t * runtime_stack,
544 : fd_pubkey_t const * builtin_program_id,
545 : fd_pubkey_t const * source_buffer_address,
546 0 : fd_capture_ctx_t * capture_ctx ) {
547 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L327 */
548 0 : target_core_bpf_t target[1];
549 0 : if( FD_UNLIKELY( !target_core_bpf_new_checked( target, builtin_program_id, accdb, xid, runtime_stack ) ) ) {
550 0 : return;
551 0 : }
552 :
553 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L328 */
554 0 : fd_tmp_account_t * source = &runtime_stack->bpf_migration.source;
555 0 : if( FD_UNLIKELY( !source_buffer_new_checked( source, accdb, xid, source_buffer_address, NULL ) ) ) {
556 0 : return;
557 0 : }
558 :
559 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L331-L332 */
560 0 : fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data;
561 0 : fd_pubkey_t program_data_address = get_program_data_address( builtin_program_id );
562 :
563 0 : ulong program_data_len = source->data_sz - BUFFER_METADATA_SIZE;
564 0 : ulong new_account_size = PROGRAMDATA_METADATA_SIZE + program_data_len;
565 :
566 0 : tmp_account_new( new_target_program_data, new_account_size );
567 0 : new_target_program_data->addr = program_data_address;
568 :
569 0 : fd_rent_t const * rent = fd_bank_rent_query( bank );
570 0 : new_target_program_data->meta.lamports = fd_rent_exempt_minimum_balance( rent, new_account_size );
571 0 : new_target_program_data->meta.executable = 0;
572 0 : fd_memcpy( new_target_program_data->meta.owner, &fd_solana_bpf_loader_upgradeable_program_id, sizeof(fd_pubkey_t) );
573 :
574 0 : fd_bpf_upgradeable_loader_state_t programdata_state[1] = {{
575 0 : .discriminant = fd_bpf_upgradeable_loader_state_enum_program_data,
576 0 : .inner = { .program_data = {
577 0 : .slot = fd_bank_slot_get( bank ),
578 0 : .upgrade_authority_address = target->upgrade_authority_address,
579 0 : .has_upgrade_authority_address = target->has_upgrade_authority_address
580 0 : }}
581 0 : }};
582 :
583 0 : fd_bincode_encode_ctx_t encode_ctx = {
584 0 : .data = new_target_program_data->data,
585 0 : .dataend = new_target_program_data->data + PROGRAMDATA_METADATA_SIZE
586 0 : };
587 0 : if( FD_UNLIKELY( FD_BINCODE_SUCCESS!=fd_bpf_upgradeable_loader_state_encode( programdata_state, &encode_ctx ) ) ) {
588 0 : return;
589 0 : }
590 :
591 0 : fd_memcpy( new_target_program_data->data + PROGRAMDATA_METADATA_SIZE,
592 0 : source->data + BUFFER_METADATA_SIZE,
593 0 : program_data_len );
594 :
595 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L338-L342 */
596 0 : ulong old_data_sz;
597 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->data_sz, source->data_sz, &old_data_sz ) ) ) return;
598 0 : ulong new_data_sz = new_target_program_data->data_sz;
599 :
600 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L359-L364 */
601 0 : ulong lamports_to_burn;
602 0 : if( FD_UNLIKELY( fd_ulong_checked_add( target->program_data_account->meta.lamports, source->meta.lamports, &lamports_to_burn ) ) ) return;
603 0 : ulong lamports_to_fund = new_target_program_data->meta.lamports;
604 :
605 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L364 */
606 0 : int err = fd_update_capitalization( bank, lamports_to_burn, lamports_to_fund );
607 0 : if( FD_UNLIKELY( err ) ) {
608 0 : FD_LOG_ERR(( "Capitalization overflow while migrating builtin program to core BPF" ));
609 0 : }
610 :
611 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L366-L371 */
612 0 : fd_pubkey_t source_addr = source->addr;
613 0 : tmp_account_store( new_target_program_data, accdb, xid, bank, capture_ctx );
614 :
615 0 : fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty;
616 0 : tmp_account_new( empty, 0UL );
617 0 : empty->addr = source_addr;
618 0 : tmp_account_store( empty, accdb, xid, bank, capture_ctx );
619 :
620 : /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L374 */
621 : /* FIXME "update account data size delta" */
622 0 : (void)old_data_sz;
623 0 : (void)new_data_sz;
624 :
625 0 : fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) );
626 0 : }
|