From 24905432c408a5971bd0616cb99e17a148d9af45 Mon Sep 17 00:00:00 2001 From: Tyera Date: Tue, 31 Jan 2023 11:15:42 -0700 Subject: [PATCH] solana-genesis: add support for initializing upgradeable programs (#29994) --- Cargo.lock | 1 + fetch-spl.sh | 10 +++- genesis/Cargo.toml | 1 + genesis/src/main.rs | 108 +++++++++++++++++++++++++++++++++++++------- 4 files changed, 101 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 701fe3413b..e76481f357 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5509,6 +5509,7 @@ name = "solana-genesis" version = "1.15.0" dependencies = [ "base64 0.13.0", + "bincode", "clap 2.33.3", "serde", "serde_json", diff --git a/fetch-spl.sh b/fetch-spl.sh index 9787bab507..a1ad3f7281 100755 --- a/fetch-spl.sh +++ b/fetch-spl.sh @@ -6,6 +6,8 @@ set -e +upgradeableLoader=BPFLoaderUpgradeab1e11111111111111111111111 + fetch_program() { declare name=$1 declare version=$2 @@ -14,7 +16,11 @@ fetch_program() { declare so=spl_$name-$version.so - genesis_args+=(--bpf-program "$address" "$loader" "$so") + if [[ $loader == "$upgradeableLoader" ]]; then + genesis_args+=(--upgradeable-program "$address" "$loader" "$so" none) + else + genesis_args+=(--bpf-program "$address" "$loader" "$so") + fi if [[ -r $so ]]; then return @@ -39,7 +45,7 @@ fetch_program() { } fetch_program token 3.5.0 TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA BPFLoader2111111111111111111111111111111111 -fetch_program token-2022 0.5.0 TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb BPFLoader2111111111111111111111111111111111 +fetch_program token-2022 0.5.0 TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb BPFLoaderUpgradeab1e11111111111111111111111 fetch_program memo 1.0.0 Memo1UhkJRfHyvLMcVucJwxXeuD728EqVDDwQDxFMNo BPFLoader1111111111111111111111111111111111 fetch_program memo 3.0.0 MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr BPFLoader2111111111111111111111111111111111 fetch_program associated-token-account 1.1.2 ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL BPFLoader2111111111111111111111111111111111 diff --git a/genesis/Cargo.toml b/genesis/Cargo.toml index 5725f711fb..3ccd22562e 100644 --- a/genesis/Cargo.toml +++ b/genesis/Cargo.toml @@ -11,6 +11,7 @@ documentation = "https://docs.rs/solana-genesis" [dependencies] base64 = "0.13.0" +bincode = "1.3.3" clap = "2.33.1" serde = "1.0.144" serde_json = "1.0.83" diff --git a/genesis/src/main.rs b/genesis/src/main.rs index 9e1f2a0c59..80bd168cd1 100644 --- a/genesis/src/main.rs +++ b/genesis/src/main.rs @@ -17,6 +17,7 @@ use { solana_runtime::hardened_unpack::MAX_GENESIS_ARCHIVE_UNPACKED_SIZE, solana_sdk::{ account::{Account, AccountSharedData, ReadableAccount, WritableAccount}, + bpf_loader_upgradeable::UpgradeableLoaderState, clock, epoch_schedule::EpochSchedule, fee_calculator::FeeRateGovernor, @@ -27,6 +28,7 @@ use { pubkey::Pubkey, rent::Rent, signature::{Keypair, Signer}, + signer::keypair::read_keypair_file, stake::state::StakeState, system_program, timing, }, @@ -376,6 +378,15 @@ fn main() -> Result<(), Box> { .multiple(true) .help("Install a SBF program at the given address"), ) + .arg( + Arg::with_name("upgradeable_program") + .long("upgradeable-program") + .value_name("ADDRESS UPGRADEABLE_LOADER BPF_PROGRAM.SO UPGRADE_AUTHORITY") + .takes_value(true) + .number_of_values(4) + .multiple(true) + .help("Install an upgradeable SBF program at the given address with the given upgrade authority (or \"none\")"), + ) .arg( Arg::with_name("inflation") .required(false) @@ -585,28 +596,32 @@ fn main() -> Result<(), Box> { add_genesis_accounts(&mut genesis_config, issued_lamports - faucet_lamports); + let parse_address = |address: &str, input_type: &str| { + address.parse::().unwrap_or_else(|err| { + eprintln!("Error: invalid {input_type} {address}: {err}"); + process::exit(1); + }) + }; + + let parse_program_data = |program: &str| { + let mut program_data = vec![]; + File::open(program) + .and_then(|mut file| file.read_to_end(&mut program_data)) + .unwrap_or_else(|err| { + eprintln!("Error: failed to read {program}: {err}"); + process::exit(1); + }); + program_data + }; + if let Some(values) = matches.values_of("bpf_program") { let values: Vec<&str> = values.collect::>(); for address_loader_program in values.chunks(3) { match address_loader_program { [address, loader, program] => { - let address = address.parse::().unwrap_or_else(|err| { - eprintln!("Error: invalid address {address}: {err}"); - process::exit(1); - }); - - let loader = loader.parse::().unwrap_or_else(|err| { - eprintln!("Error: invalid loader {loader}: {err}"); - process::exit(1); - }); - - let mut program_data = vec![]; - File::open(program) - .and_then(|mut file| file.read_to_end(&mut program_data)) - .unwrap_or_else(|err| { - eprintln!("Error: failed to read {program}: {err}"); - process::exit(1); - }); + let address = parse_address(address, "address"); + let loader = parse_address(loader, "loader"); + let program_data = parse_program_data(program); genesis_config.add_account( address, AccountSharedData::from(Account { @@ -623,6 +638,65 @@ fn main() -> Result<(), Box> { } } + if let Some(values) = matches.values_of("upgradeable_program") { + let values: Vec<&str> = values.collect::>(); + for address_loader_program_upgrade_authority in values.chunks(4) { + match address_loader_program_upgrade_authority { + [address, loader, program, upgrade_authority] => { + let address = parse_address(address, "address"); + let loader = parse_address(loader, "loader"); + let program_data_elf = parse_program_data(program); + let upgrade_authority_address = if *upgrade_authority == "none" { + Pubkey::default() + } else { + upgrade_authority.parse::().unwrap_or_else(|_| { + read_keypair_file(upgrade_authority).map(|keypair| keypair.pubkey()).unwrap_or_else(|err| { + eprintln!("Error: invalid upgrade_authority {upgrade_authority}: {err}"); + process::exit(1); + }) + }) + }; + + let (programdata_address, _) = + Pubkey::find_program_address(&[address.as_ref()], &loader); + let mut program_data = + bincode::serialize(&UpgradeableLoaderState::ProgramData { + slot: 0, + upgrade_authority_address: Some(upgrade_authority_address), + }) + .unwrap(); + program_data.extend_from_slice(&program_data_elf); + genesis_config.add_account( + programdata_address, + AccountSharedData::from(Account { + lamports: genesis_config.rent.minimum_balance(program_data.len()), + data: program_data, + owner: loader, + executable: false, + rent_epoch: 0, + }), + ); + + let program_data = bincode::serialize(&UpgradeableLoaderState::Program { + programdata_address, + }) + .unwrap(); + genesis_config.add_account( + address, + AccountSharedData::from(Account { + lamports: genesis_config.rent.minimum_balance(program_data.len()), + data: program_data, + owner: loader, + executable: true, + rent_epoch: 0, + }), + ); + } + _ => unreachable!(), + } + } + } + solana_logger::setup(); create_new_ledger( &ledger_path,