|
8 | 8 | #include "fd_hashes.h" |
9 | 9 | #include "../accdb/fd_accdb_sync.h" |
10 | 10 | #include "../../ballet/sha256/fd_sha256.h" |
| 11 | +#include "../../ballet/sbpf/fd_sbpf_loader.h" |
| 12 | +#include "../progcache/fd_prog_load.h" |
11 | 13 | #include <assert.h> |
12 | 14 |
|
13 | 15 | static fd_pubkey_t |
@@ -257,6 +259,86 @@ target_core_bpf_new_checked( target_core_bpf_t * target_core_bpf, |
257 | 259 | return target_core_bpf; |
258 | 260 | } |
259 | 261 |
|
| 262 | +/* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/target_bpf_v2.rs#L13-L18 */ |
| 263 | +struct target_bpf_v2 { |
| 264 | + fd_tmp_account_t * program_account; |
| 265 | + fd_pubkey_t program_data_address; |
| 266 | + ulong program_data_account_lamports; |
| 267 | +}; |
| 268 | + |
| 269 | +typedef struct target_bpf_v2 target_bpf_v2_t; |
| 270 | + |
| 271 | +/* 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 */ |
| 272 | +static target_bpf_v2_t * |
| 273 | +target_bpf_v2_new_checked( target_bpf_v2_t * target_bpf_v2, |
| 274 | + fd_pubkey_t const * program_address, |
| 275 | + int allow_prefunded, |
| 276 | + fd_accdb_user_t * accdb, |
| 277 | + fd_funk_txn_xid_t const * xid, |
| 278 | + fd_runtime_stack_t * runtime_stack ) { |
| 279 | + |
| 280 | + /* 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 */ |
| 281 | + fd_tmp_account_t * program_account = &runtime_stack->bpf_migration.program_account; |
| 282 | + if( FD_UNLIKELY( !tmp_account_read( program_account, accdb, xid, program_address ) ) ) { |
| 283 | + /* CoreBpfMigrationError::AccountNotFound(*program_address) */ |
| 284 | + return NULL; |
| 285 | + } |
| 286 | + |
| 287 | + /* 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 */ |
| 288 | + if( FD_UNLIKELY( 0!=memcmp( program_account->meta.owner, &fd_solana_bpf_loader_program_id, FD_PUBKEY_FOOTPRINT ) ) ) { |
| 289 | + /* CoreBpfMigrationError::IncorrectOwner(*program_address) */ |
| 290 | + return NULL; |
| 291 | + } |
| 292 | + |
| 293 | + /* 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 */ |
| 294 | + if( FD_UNLIKELY( !program_account->meta.executable ) ) { |
| 295 | + /* CoreBpfMigrationError::ProgramAccountNotExecutable(*program_address) */ |
| 296 | + return NULL; |
| 297 | + } |
| 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#L47 */ |
| 300 | + fd_pubkey_t program_data_address = get_program_data_address( program_address ); |
| 301 | + |
| 302 | + /* 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 */ |
| 303 | + ulong program_data_account_lamports = 0UL; |
| 304 | + do { |
| 305 | + fd_accdb_ro_t ro[1]; |
| 306 | + int progdata_exists = !!fd_accdb_open_ro( accdb, ro, xid, &program_data_address ); |
| 307 | + |
| 308 | + /* 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 */ |
| 309 | + if( FD_LIKELY( allow_prefunded ) ) { |
| 310 | + /* The program data account should not exist, but a system |
| 311 | + account with funded lamports is acceptable. |
| 312 | +
|
| 313 | + 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 */ |
| 314 | + if( FD_UNLIKELY( progdata_exists ) ) { |
| 315 | + if( FD_UNLIKELY( 0!=memcmp( fd_accdb_ref_owner( ro ), &fd_solana_system_program_id, FD_PUBKEY_FOOTPRINT ) ) ) { |
| 316 | + /* CoreBpfMigrationError::ProgramHasDataAccount(*program_address) */ |
| 317 | + fd_accdb_close_ro( accdb, ro ); |
| 318 | + return NULL; |
| 319 | + } else { |
| 320 | + program_data_account_lamports = fd_accdb_ref_lamports( ro ); |
| 321 | + fd_accdb_close_ro( accdb, ro ); |
| 322 | + } |
| 323 | + } |
| 324 | + } else { |
| 325 | + /* 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 */ |
| 326 | + if( FD_UNLIKELY( progdata_exists ) ) { |
| 327 | + /* CoreBpfMigrationError::ProgramHasDataAccount(*program_address) */ |
| 328 | + fd_accdb_close_ro( accdb, ro ); |
| 329 | + return NULL; |
| 330 | + } |
| 331 | + } |
| 332 | + } while(0); |
| 333 | + |
| 334 | + *target_bpf_v2 = (target_bpf_v2_t) { |
| 335 | + .program_account = program_account, |
| 336 | + .program_data_address = program_data_address, |
| 337 | + .program_data_account_lamports = program_data_account_lamports |
| 338 | + }; |
| 339 | + return target_bpf_v2; |
| 340 | +} |
| 341 | + |
260 | 342 | /* https://github.com/anza-xyz/agave/blob/v3.1.7/runtime/src/bank/builtins/core_bpf_migration/source_buffer.rs#L51-L75 */ |
261 | 343 |
|
262 | 344 | static fd_tmp_account_t * |
@@ -624,3 +706,115 @@ fd_upgrade_core_bpf_program( fd_bank_t * bank, |
624 | 706 |
|
625 | 707 | fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) ); |
626 | 708 | } |
| 709 | + |
| 710 | +/* Mimics upgrade_loader_v2_program_with_loader_v3_program(). |
| 711 | + https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L402-L474 */ |
| 712 | +void |
| 713 | +fd_upgrade_loader_v2_program_with_loader_v3_program( fd_bank_t * bank, |
| 714 | + fd_accdb_user_t * accdb, |
| 715 | + fd_funk_txn_xid_t const * xid, |
| 716 | + fd_runtime_stack_t * runtime_stack, |
| 717 | + fd_pubkey_t const * loader_v2_program_address, |
| 718 | + fd_pubkey_t const * source_buffer_address, |
| 719 | + int allow_prefunded, |
| 720 | + fd_capture_ctx_t * capture_ctx ) { |
| 721 | + |
| 722 | + /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L411-L412 */ |
| 723 | + target_bpf_v2_t target[1]; |
| 724 | + if( FD_UNLIKELY( !target_bpf_v2_new_checked( |
| 725 | + target, |
| 726 | + loader_v2_program_address, |
| 727 | + allow_prefunded, |
| 728 | + accdb, |
| 729 | + xid, |
| 730 | + runtime_stack ) ) ) |
| 731 | + return; |
| 732 | + |
| 733 | + /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L413 */ |
| 734 | + fd_tmp_account_t * source = &runtime_stack->bpf_migration.source; |
| 735 | + if( FD_UNLIKELY( !source_buffer_new_checked( source, accdb, xid, source_buffer_address, NULL ) ) ) |
| 736 | + return; |
| 737 | + |
| 738 | + fd_rent_t const * rent = fd_bank_rent_query( bank ); |
| 739 | + ulong const slot = fd_bank_slot_get ( bank ); |
| 740 | + |
| 741 | + /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L416-L417 */ |
| 742 | + fd_tmp_account_t * new_target_program = &runtime_stack->bpf_migration.new_target_program; |
| 743 | + if( FD_UNLIKELY( !new_target_program_account( new_target_program, (target_builtin_t const *)target, rent ) ) ) |
| 744 | + return; |
| 745 | + new_target_program->addr = *loader_v2_program_address; |
| 746 | + |
| 747 | + /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L419-L421 */ |
| 748 | + fd_tmp_account_t * new_target_program_data = &runtime_stack->bpf_migration.new_target_program_data; |
| 749 | + if( FD_UNLIKELY( !new_target_program_data_account( new_target_program_data, source, NULL, rent, slot ) ) ) { |
| 750 | + return; |
| 751 | + } |
| 752 | + new_target_program_data->addr = target->program_data_address; |
| 753 | + |
| 754 | + /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L427-L435 */ |
| 755 | + ulong old_data_sz; |
| 756 | + if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->data_sz, source->data_sz, &old_data_sz ) ) ) return; |
| 757 | + |
| 758 | + /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L432-L435 */ |
| 759 | + ulong new_data_sz; |
| 760 | + if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->data_sz, new_target_program_data->data_sz, &new_data_sz ) ) ) return; |
| 761 | + |
| 762 | + assert( new_target_program_data->data_sz>=PROGRAMDATA_METADATA_SIZE ); |
| 763 | + |
| 764 | + /* Validate the ELF. Agave calls directly_invoke_loader_v3_deploy, |
| 765 | + which validates the ELF and aborts the migration if the ELF is |
| 766 | + invalid. |
| 767 | +
|
| 768 | + We don't invalidate the program cache here, because upgrades are |
| 769 | + done at the epoch boundary, so the cache entry is invalidated |
| 770 | + automatically. |
| 771 | +
|
| 772 | + https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L437-L443 */ |
| 773 | + do { |
| 774 | + uchar const * elf = (uchar const *)new_target_program_data->data + PROGRAMDATA_METADATA_SIZE; |
| 775 | + ulong elf_sz = new_target_program_data->data_sz - PROGRAMDATA_METADATA_SIZE; |
| 776 | + |
| 777 | + fd_prog_versions_t versions = fd_prog_versions( fd_bank_features_query( bank ), slot ); |
| 778 | + fd_sbpf_loader_config_t loader_config = { |
| 779 | + .sbpf_min_version = versions.min_sbpf_version, |
| 780 | + .sbpf_max_version = versions.max_sbpf_version, |
| 781 | + }; |
| 782 | + fd_sbpf_elf_info_t elf_info[1]; |
| 783 | + if( FD_UNLIKELY( fd_sbpf_elf_peek( elf_info, elf, elf_sz, &loader_config )!=FD_SBPF_ELF_SUCCESS ) ) { |
| 784 | + return; |
| 785 | + } |
| 786 | + } while(0); |
| 787 | + |
| 788 | + /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L451-L459 */ |
| 789 | + ulong lamports_to_burn; |
| 790 | + if( FD_UNLIKELY( fd_ulong_checked_add( target->program_account->meta.lamports, source->meta.lamports, &lamports_to_burn ) ) ) return; |
| 791 | + if( FD_UNLIKELY( fd_ulong_checked_add( lamports_to_burn, target->program_data_account_lamports, &lamports_to_burn ) ) ) return; |
| 792 | + |
| 793 | + ulong lamports_to_fund; |
| 794 | + if( FD_UNLIKELY( fd_ulong_checked_add( new_target_program->meta.lamports, new_target_program_data->meta.lamports, &lamports_to_fund ) ) ) return; |
| 795 | + |
| 796 | + /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L460 */ |
| 797 | + if( FD_UNLIKELY( fd_update_capitalization( bank, lamports_to_burn, lamports_to_fund ) ) ) { |
| 798 | + FD_LOG_CRIT(( "invariant violation: capitalization overflow while upgrading Loader v2 program to Loader v3" )); |
| 799 | + } |
| 800 | + |
| 801 | + /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L462-L468 */ |
| 802 | + tmp_account_store( new_target_program, accdb, xid, bank, capture_ctx ); |
| 803 | + tmp_account_store( new_target_program_data, accdb, xid, bank, capture_ctx ); |
| 804 | + |
| 805 | + fd_tmp_account_t * empty = &runtime_stack->bpf_migration.empty; |
| 806 | + tmp_account_new( empty, 0UL ); |
| 807 | + empty->addr = source->addr; |
| 808 | + tmp_account_store( empty, accdb, xid, bank, capture_ctx ); |
| 809 | + |
| 810 | + /* TODO: Agave updates "delta_off_chain", using these two fields, |
| 811 | + which is not consensus-critical so we don't update this in our |
| 812 | + migration code. |
| 813 | +
|
| 814 | + However, if we ever enable Firedancer-produced snapshots we will |
| 815 | + need to track this correctly. */ |
| 816 | + (void)old_data_sz; |
| 817 | + (void)new_data_sz; |
| 818 | + |
| 819 | + fd_memset( &runtime_stack->bpf_migration, 0, sizeof(runtime_stack->bpf_migration) ); |
| 820 | +} |
0 commit comments