From 6f687e510cf5cfef366f2d14e2cf4897dd3a02e2 Mon Sep 17 00:00:00 2001 From: Joe Date: Fri, 18 Aug 2023 10:41:19 -0600 Subject: [PATCH] stripped back to feature-specific case only --- runtime/src/bank.rs | 117 ++++--- runtime/src/bank/tests.rs | 673 +++----------------------------------- 2 files changed, 99 insertions(+), 691 deletions(-) diff --git a/runtime/src/bank.rs b/runtime/src/bank.rs index a5c1c8015d48bf..fff14533661d74 100644 --- a/runtime/src/bank.rs +++ b/runtime/src/bank.rs @@ -8119,20 +8119,30 @@ impl Bank { } } - fn replace_account( + fn replace_account( &mut self, old_address: &Pubkey, new_address: &Pubkey, - old_account: Option<&AccountSharedData>, - new_account: &AccountSharedData, - ) { + old_account: Option<&O>, + new_account: &N, + ) where + O: ReadableAccount + Sync + ZeroLamport, + N: ReadableAccount + Sync + ZeroLamport, + { let (old_lamports, old_len) = match old_account { Some(old_account) => (old_account.lamports(), old_account.data().len()), None => (0, 0), }; + + // Burn lamports in the old account self.capitalization.fetch_sub(old_lamports, Relaxed); + + // Transfer new account to old account self.store_account(old_address, new_account); + + // Clear new account self.store_account(new_address, &AccountSharedData::default()); + self.calculate_and_update_accounts_data_size_delta_off_chain( old_len, new_account.data().len(), @@ -8147,9 +8157,32 @@ impl Bank { new_address: &Pubkey, datapoint_name: &'static str, ) { - if let Some(new_account) = self.get_account_with_fixed_root(new_address) { - datapoint_info!(datapoint_name, ("slot", self.slot, i64)); + if let Some(old_account) = self.get_account_with_fixed_root(old_address) { + if let Some(new_account) = self.get_account_with_fixed_root(new_address) { + datapoint_info!(datapoint_name, ("slot", self.slot, i64)); + + self.replace_account(old_address, new_address, Some(&old_account), &new_account); + // Unload a program from the bank's cache + self.loaded_programs_cache + .write() + .unwrap() + .remove_programs([*old_address].into_iter()); + } + } + } + + /// Use to replace an empty account with a program by feature activation + #[allow(dead_code)] + fn replace_empty_account_with_upgradeable_program( + &mut self, + old_address: &Pubkey, + new_address: &Pubkey, + datapoint_name: &'static str, + ) { + // Must be attempting to replace an empty account with a program + // account _and_ data account + if let Some(new_account) = self.get_account_with_fixed_root(new_address) { let (old_data_address, _) = Pubkey::find_program_address( &[old_address.as_ref()], &bpf_loader_upgradeable::id(), @@ -8158,47 +8191,15 @@ impl Bank { &[new_address.as_ref()], &bpf_loader_upgradeable::id(), ); - - // If a data account is also provided with this new program - // account, then we want to update the existing data account if let Some(new_data_account) = self.get_account_with_fixed_root(&new_data_address) { - let data = old_data_address.as_ref().to_vec(); + datapoint_info!(datapoint_name, ("slot", self.slot, i64)); - let change_in_cap = - if let Some(old_account) = self.get_account_with_fixed_root(old_address) { - // If the old program account exists and the data is not - // the PDA of the data account, overwrite the data with the - // PDA and fund it with any lamports for rent if necessary - if old_account.data() != data { - let lamports = old_account - .lamports() - .max(self.get_minimum_balance_for_rent_exemption(data.len())); - let overwrite = Account { - lamports, - data, - ..Account::from(new_account.clone()) - }; - self.store_account(old_address, &overwrite); - new_account.lamports() + old_account.lamports() - lamports - } else { - new_account.lamports() - } - } else { - // If the old program account does not exist, create it - // with the PDA as its data and fund it with rent-exempt - // lamports - let lamports = self.get_minimum_balance_for_rent_exemption(data.len()); - let overwrite = Account { - lamports, - data, - ..Account::from(new_account.clone()) - }; - self.store_account(old_address, &overwrite); - new_account.lamports() - lamports - }; + let data = old_data_address.as_ref().to_vec(); + let lamports = self.get_minimum_balance_for_rent_exemption(data.len()); - // Replace the old data account with the new data account + // Replace the old data account with the new one // If the old data account does not exist, it will be created + // If the new data account does exist, it will be overwritten self.replace_account( &old_data_address, &new_data_address, @@ -8206,31 +8207,23 @@ impl Bank { &new_data_account, ); - // Clear the new program account - self.store_account(new_address, &AccountSharedData::default()); - - // Update capitalization - self.capitalization.fetch_sub(change_in_cap, Relaxed); - } else if self - .get_account_with_fixed_root(&old_data_address) - .is_none() - { - // A data account does not exist for the new program - // Replace the old program account with the new program account - // If the old program account doesn't exist, it will be created + // Write the data account's PDA into the program account + let created_program_account = Account { + lamports, + data, + ..new_account.clone().into() + }; self.replace_account( old_address, new_address, self.get_account_with_fixed_root(old_address).as_ref(), - &new_account, + &created_program_account, ); - } - // Unload a program from the bank's cache - self.loaded_programs_cache - .write() - .unwrap() - .remove_programs([*old_address].into_iter()); + // Any remaining lamports in the new program account are burnt + let change_in_cap = new_account.lamports() - lamports; + self.capitalization.fetch_sub(change_in_cap, Relaxed); + } } } diff --git a/runtime/src/bank/tests.rs b/runtime/src/bank/tests.rs index da9a65faa56152..e07dacd22503db 100644 --- a/runtime/src/bank/tests.rs +++ b/runtime/src/bank/tests.rs @@ -8030,8 +8030,8 @@ fn test_program_replace_set_up_account( } #[test] -fn test_program_replace_non_upgradable_base_case() { - // Non-Upgradable program +fn test_program_replace_non_upgradeable() { + // Non-upgradeable program // - Old: [Old program data] // - New: [*New program data] // @@ -8084,243 +8084,7 @@ fn test_program_replace_non_upgradable_base_case() { } #[test] -fn test_program_replace_non_upgradable_create_data_add_rent() { - // Non-Upgradable program - // - Old: [Old program data] (smaller than minimum rent-exempt size) - // - New: PDA(NewData) - // - NewData: [*New program data] - // - // Should replace the program account with the PDA of the data account, - // and create the data account: - // - Old: PDA(OldData) - // - OldData: [*New program data] - let bpf_id = bpf_loader::id(); - let bpf_upgradable_id = bpf_loader_upgradeable::id(); - let mut bank = create_simple_test_bank(0); - - let old = Pubkey::new_unique(); - let old_bytes = vec![0, 0, 0, 0]; // Smaller than 32 bytes - let old_lamports = bank.get_minimum_balance_for_rent_exemption(old_bytes.len()); - let (old_data, _) = Pubkey::find_program_address(&[old.as_ref()], &bpf_upgradable_id); - test_program_replace_set_up_account(&mut bank, &old, old_lamports, old_bytes, &bpf_id, true); - - let new = Pubkey::new_unique(); - let (new_data, _) = Pubkey::find_program_address(&[new.as_ref()], &bpf_upgradable_id); - let new_bytes = new_data.to_bytes().to_vec(); - let new_lamports = bank.get_minimum_balance_for_rent_exemption(new_bytes.len()); - let new_data_bytes = vec![6; 30]; - let new_data_lamports = bank.get_minimum_balance_for_rent_exemption(new_data_bytes.len()); - test_program_replace_set_up_account( - &mut bank, - &new, - new_lamports, - new_bytes, - &bpf_upgradable_id, - true, - ); - test_program_replace_set_up_account( - &mut bank, - &new_data, - new_data_lamports, - new_data_bytes.clone(), - &bpf_upgradable_id, - false, - ); - - let original_capitalization = bank.capitalization(); - - bank.replace_program_account(&old, &new, "bank-apply_program_replacement"); - - // Old program account's balance was adjusted to pay for minimum rent for - // the PDA (32 bytes) - // - // Note: In this test, the original lamports were _less_ than required - // rent for 32 bytes, so lamports were added - assert_eq!( - bank.get_balance(&old), - bank.get_minimum_balance_for_rent_exemption(old_data.to_bytes().len()) - ); - - // Old data account's balance is now the new data account's balance - // (newly created) - assert_eq!(bank.get_balance(&old_data), new_data_lamports); - - // New program accounts are now empty - assert_eq!(bank.get_balance(&new), 0); - assert_eq!(bank.get_balance(&new_data), 0); - - // Old program account now holds the PDA, ie: - // - Old: PDA(OldData) - let old_account = bank.get_account(&old).unwrap(); - assert_eq!(old_account.data(), &old_data.to_bytes().to_vec()); - - // Old data account has been created & now holds the new data, ie: - // - OldData: [*New program data] - let old_data_account = bank.get_account(&old_data).unwrap(); - assert_eq!(old_data_account.data(), &new_data_bytes); - - // Ownership & executable match the new program accounts - assert_eq!(old_account.owner(), &bpf_upgradable_id); - assert!(old_account.executable()); - assert_eq!(old_data_account.owner(), &bpf_upgradable_id); - assert!(!old_data_account.executable()); - - // The remaining lamports from both program accounts minus the rent-exempt - // minimum were burnt - let burnt_after_rent = new_lamports + old_lamports - - bank.get_minimum_balance_for_rent_exemption(old_data.to_bytes().len()); - assert_eq!( - bank.capitalization(), - original_capitalization - burnt_after_rent - ); -} - -#[test] -fn test_program_replace_non_upgradable_create_data_dont_add_rent() { - // Non-Upgradable program - // - Old: [Old program data] (larger than minimum rent-exempt size) - // - New: PDA(NewData) - // - NewData: [*New program data] - // - // Should replace the program account with the PDA of the data account, - // and create the data account: - // - Old: PDA(OldData) - // - OldData: [*New program data] - let bpf_id = bpf_loader::id(); - let bpf_upgradable_id = bpf_loader_upgradeable::id(); - let mut bank = create_simple_test_bank(0); - - let old = Pubkey::new_unique(); - let old_bytes = vec![0; 44]; // Larger than 32 bytes - let old_lamports = bank.get_minimum_balance_for_rent_exemption(old_bytes.len()); - let (old_data, _) = Pubkey::find_program_address(&[old.as_ref()], &bpf_upgradable_id); - test_program_replace_set_up_account(&mut bank, &old, old_lamports, old_bytes, &bpf_id, true); - - let new = Pubkey::new_unique(); - let (new_data, _) = Pubkey::find_program_address(&[new.as_ref()], &bpf_upgradable_id); - let new_bytes = new_data.to_bytes().to_vec(); - let new_lamports = bank.get_minimum_balance_for_rent_exemption(new_bytes.len()); - let new_data_bytes = vec![6; 30]; - let new_data_lamports = bank.get_minimum_balance_for_rent_exemption(new_data_bytes.len()); - test_program_replace_set_up_account( - &mut bank, - &new, - new_lamports, - new_bytes, - &bpf_upgradable_id, - true, - ); - test_program_replace_set_up_account( - &mut bank, - &new_data, - new_data_lamports, - new_data_bytes.clone(), - &bpf_upgradable_id, - false, - ); - - let original_capitalization = bank.capitalization(); - - bank.replace_program_account(&old, &new, "bank-apply_program_replacement"); - - // Old program account's balance was _not_ adjusted to pay for minimum rent - // for the PDA - // - // Note: In this test, the original lamports were _greater_ than required - // rent for 32 bytes, so _no_ lamports were added - assert_eq!(bank.get_balance(&old), old_lamports); - - // Old data account's balance is now the new data account's balance - // (newly created) - assert_eq!(bank.get_balance(&old_data), new_data_lamports); - - // New program accounts are now empty - assert_eq!(bank.get_balance(&new), 0); - assert_eq!(bank.get_balance(&new_data), 0); - - // Old program account now holds the PDA, ie: - // - Old: PDA(OldData) - let old_account = bank.get_account(&old).unwrap(); - assert_eq!(old_account.data(), &old_data.to_bytes().to_vec()); - - // Old data account has been created & now holds the new data, ie: - // - OldData: [*New program data] - let old_data_account = bank.get_account(&old_data).unwrap(); - assert_eq!(old_data_account.data(), &new_data_bytes); - - // Ownership & executable match the new program accounts - assert_eq!(old_account.owner(), &bpf_upgradable_id); - assert!(old_account.executable()); - assert_eq!(old_data_account.owner(), &bpf_upgradable_id); - assert!(!old_data_account.executable()); - - // Lamports from the new program account were burnt - assert_eq!( - bank.capitalization(), - original_capitalization - new_lamports - ); -} - -#[test] -fn test_program_replace_does_not_exist() { - // Non-Existent program - // - Old: ** Does not exist! ** - // - New: [*Arbitrary data] - // - // Should create the program account, ie: - // - Old: [*Arbitrary data] - let bpf_id = bpf_loader::id(); - let mut bank = create_simple_test_bank(0); - - let old = Pubkey::new_unique(); - - let new = Pubkey::new_unique(); - let new_bytes = vec![6; 30]; - let new_lamports = bank.get_minimum_balance_for_rent_exemption(new_bytes.len()); - test_program_replace_set_up_account( - &mut bank, - &new, - new_lamports, - new_bytes.clone(), - &bpf_id, - true, - ); - - let original_capitalization = bank.capitalization(); - - bank.replace_program_account(&old, &new, "bank-apply_program_replacement"); - - // Old program account was created and funded to pay for minimum rent - // for the arbitrary data - assert_eq!( - bank.get_balance(&old), - bank.get_minimum_balance_for_rent_exemption(new_bytes.len()) - ); - - // New program account is now empty - assert_eq!(bank.get_balance(&new), 0); - - // Old program account holds new program account bytes, ie: - // - Old: [*Arbitrary data] - let old_account = bank.get_account(&old).unwrap(); - assert_eq!(old_account.data(), &new_bytes); - - // Ownership & executable match the new program account - assert_eq!(old_account.owner(), &bpf_id); - assert!(old_account.executable()); - - // The remaining lamports from both program accounts minus the rent-exempt - // minimum were burnt - let burnt_after_rent = - new_lamports - bank.get_minimum_balance_for_rent_exemption(new_bytes.len()); - assert_eq!( - bank.capitalization(), - original_capitalization - burnt_after_rent - ); -} - -#[test] -fn test_program_replace_does_not_exist_create_data() { +fn test_replace_empty_account_with_upgradeable_program() { // Non-Existent program // - Old: ** Does not exist! ** // - New: PDA(NewData) @@ -8329,14 +8093,14 @@ fn test_program_replace_does_not_exist_create_data() { // Should create the program account and the data account, ie: // - Old: PDA(OldData) // - OldData: [Old program data] - let bpf_upgradable_id = bpf_loader_upgradeable::id(); + let bpf_upgradeable_id = bpf_loader_upgradeable::id(); let mut bank = create_simple_test_bank(0); let old = Pubkey::new_unique(); - let (old_data, _) = Pubkey::find_program_address(&[old.as_ref()], &bpf_upgradable_id); + let (old_data, _) = Pubkey::find_program_address(&[old.as_ref()], &bpf_upgradeable_id); let new = Pubkey::new_unique(); - let (new_data, _) = Pubkey::find_program_address(&[new.as_ref()], &bpf_upgradable_id); + let (new_data, _) = Pubkey::find_program_address(&[new.as_ref()], &bpf_upgradeable_id); let new_bytes = new_data.to_bytes().to_vec(); let new_lamports = bank.get_minimum_balance_for_rent_exemption(new_bytes.len()); let new_data_bytes = vec![6; 30]; @@ -8346,7 +8110,7 @@ fn test_program_replace_does_not_exist_create_data() { &new, new_lamports, new_bytes, - &bpf_upgradable_id, + &bpf_upgradeable_id, true, ); test_program_replace_set_up_account( @@ -8354,13 +8118,17 @@ fn test_program_replace_does_not_exist_create_data() { &new_data, new_data_lamports, new_data_bytes.clone(), - &bpf_upgradable_id, + &bpf_upgradeable_id, false, ); let original_capitalization = bank.capitalization(); - bank.replace_program_account(&old, &new, "bank-apply_program_replacement"); + bank.replace_empty_account_with_upgradeable_program( + &old, + &new, + "bank-apply_program_replacement", + ); // Old program account was created and funded to pay for minimum rent // for the PDA @@ -8387,9 +8155,9 @@ fn test_program_replace_does_not_exist_create_data() { assert_eq!(old_data_account.data(), &new_data_bytes); // Ownership & executable match the new program accounts - assert_eq!(old_account.owner(), &bpf_upgradable_id); + assert_eq!(old_account.owner(), &bpf_upgradeable_id); assert!(old_account.executable()); - assert_eq!(old_data_account.owner(), &bpf_upgradable_id); + assert_eq!(old_data_account.owner(), &bpf_upgradeable_id); assert!(!old_data_account.executable()); // The remaining lamports from both program accounts minus the rent-exempt @@ -8403,7 +8171,7 @@ fn test_program_replace_does_not_exist_create_data() { } #[test] -fn test_program_replace_is_native_account() { +fn test_replace_empty_account_with_upgradeable_program_is_native_account() { // Native program // - Old: ** Native account (ie. `Feature11111111`) ** // - New: PDA(NewData) @@ -8412,14 +8180,14 @@ fn test_program_replace_is_native_account() { // Should create the program account and the data account, ie: // - Old: PDA(OldData) // - OldData: [Old program data] - let bpf_upgradable_id = bpf_loader_upgradeable::id(); + let bpf_upgradeable_id = bpf_loader_upgradeable::id(); let mut bank = create_simple_test_bank(0); - let old = Pubkey::new_unique(); - let (old_data, _) = Pubkey::find_program_address(&[old.as_ref()], &bpf_upgradable_id); + let old = feature::id(); // `Feature11111111` + let (old_data, _) = Pubkey::find_program_address(&[old.as_ref()], &bpf_upgradeable_id); let new = Pubkey::new_unique(); - let (new_data, _) = Pubkey::find_program_address(&[new.as_ref()], &bpf_upgradable_id); + let (new_data, _) = Pubkey::find_program_address(&[new.as_ref()], &bpf_upgradeable_id); let new_bytes = new_data.to_bytes().to_vec(); let new_lamports = bank.get_minimum_balance_for_rent_exemption(new_bytes.len()); let new_data_bytes = vec![6; 30]; @@ -8429,7 +8197,7 @@ fn test_program_replace_is_native_account() { &new, new_lamports, new_bytes, - &bpf_upgradable_id, + &bpf_upgradeable_id, true, ); test_program_replace_set_up_account( @@ -8437,13 +8205,17 @@ fn test_program_replace_is_native_account() { &new_data, new_data_lamports, new_data_bytes.clone(), - &bpf_upgradable_id, + &bpf_upgradeable_id, false, ); let original_capitalization = bank.capitalization(); - bank.replace_program_account(&old, &new, "bank-apply_program_replacement"); + bank.replace_empty_account_with_upgradeable_program( + &old, + &new, + "bank-apply_program_replacement", + ); // Old program account was created and funded to pay for minimum rent // for the PDA @@ -8470,9 +8242,9 @@ fn test_program_replace_is_native_account() { assert_eq!(old_data_account.data(), &new_data_bytes); // Ownership & executable match the new program accounts - assert_eq!(old_account.owner(), &bpf_upgradable_id); + assert_eq!(old_account.owner(), &bpf_upgradeable_id); assert!(old_account.executable()); - assert_eq!(old_data_account.owner(), &bpf_upgradable_id); + assert_eq!(old_data_account.owner(), &bpf_upgradeable_id); assert!(!old_data_account.executable()); // The remaining lamports from both program accounts minus the rent-exempt @@ -8486,79 +8258,8 @@ fn test_program_replace_is_native_account() { } #[test] -fn test_program_replace_does_not_exist_but_data_does() { - // Non-Upgradable program - // - Old: ** Does not exist! ** - // - OldData: [Old program data] - // - New: [*Arbitrary data] - // - // This is NOT allowed and should leave the program unchanged: - // - Old: ** Does not exist! ** - // - OldData: [Old program data] - let bpf_id = bpf_loader::id(); - let bpf_upgradable_id = bpf_loader_upgradeable::id(); - let mut bank = create_simple_test_bank(0); - - let old = Pubkey::new_unique(); - let (old_data, _) = Pubkey::find_program_address(&[old.as_ref()], &bpf_upgradable_id); - let old_data_bytes = vec![4; 10]; - let old_data_lamports = bank.get_minimum_balance_for_rent_exemption(old_data_bytes.len()); - test_program_replace_set_up_account( - &mut bank, - &old_data, - old_data_lamports, - old_data_bytes.clone(), - &bpf_upgradable_id, - false, - ); - - let new = Pubkey::new_unique(); - let new_bytes = vec![2; 12]; - let new_lamports = bank.get_minimum_balance_for_rent_exemption(new_bytes.len()); - test_program_replace_set_up_account( - &mut bank, - &new, - new_lamports, - new_bytes.clone(), - &bpf_id, - true, - ); - - let original_capitalization = bank.capitalization(); - - bank.replace_program_account(&old, &new, "bank-apply_program_replacement"); - - // All balances are unchanged - assert_eq!(bank.get_balance(&old), 0); - assert_eq!(bank.get_balance(&old_data), old_data_lamports); - assert_eq!(bank.get_balance(&new), new_lamports); - - // Old program accounts still does not exist - assert_eq!(bank.get_account(&old), None); - - // Old data accounts' data is unchanged - // - OldData: [Old program data] - let old_data_account = bank.get_account(&old_data).unwrap(); - assert_eq!(old_data_account.data(), &old_data_bytes); - - // New program account is unchanged - // - New: [*Arbitrary data] - let new_account = bank.get_account(&new).unwrap(); - assert_eq!(new_account.data(), &new_bytes); - - // Ownership & executable are unchanged - assert_eq!(old_data_account.owner(), &bpf_upgradable_id); - assert!(!old_data_account.executable()); - assert_eq!(new_account.owner(), &bpf_id); - assert!(new_account.executable()); - - // Lamports were unchanged across the board - assert_eq!(bank.capitalization(), original_capitalization); -} - -#[test] -fn test_program_replace_does_not_exist_but_data_does_with_data() { - // Non-Upgradable program +fn test_replace_empty_account_with_upgradeable_program_has_data() { + // Non-upgradeable program // - Old: ** Does not exist! ** // - OldData: [Old program data] // - New: PDA(NewData) @@ -8567,11 +8268,11 @@ fn test_program_replace_does_not_exist_but_data_does_with_data() { // Should create the program account and replace the data account: // - Old: PDA(OldData) // - OldData: [*New program data] - let bpf_upgradable_id = bpf_loader_upgradeable::id(); + let bpf_upgradeable_id = bpf_loader_upgradeable::id(); let mut bank = create_simple_test_bank(0); let old = Pubkey::new_unique(); - let (old_data, _) = Pubkey::find_program_address(&[old.as_ref()], &bpf_upgradable_id); + let (old_data, _) = Pubkey::find_program_address(&[old.as_ref()], &bpf_upgradeable_id); let old_data_bytes = vec![4; 10]; let old_data_lamports = bank.get_minimum_balance_for_rent_exemption(old_data_bytes.len()); test_program_replace_set_up_account( @@ -8579,12 +8280,12 @@ fn test_program_replace_does_not_exist_but_data_does_with_data() { &old_data, old_data_lamports, old_data_bytes, - &bpf_upgradable_id, + &bpf_upgradeable_id, false, ); let new = Pubkey::new_unique(); - let (new_data, _) = Pubkey::find_program_address(&[new.as_ref()], &bpf_upgradable_id); + let (new_data, _) = Pubkey::find_program_address(&[new.as_ref()], &bpf_upgradeable_id); let new_bytes = new_data.to_bytes().to_vec(); let new_lamports = bank.get_minimum_balance_for_rent_exemption(new_bytes.len()); let new_data_bytes = vec![6; 30]; @@ -8594,7 +8295,7 @@ fn test_program_replace_does_not_exist_but_data_does_with_data() { &new, new_lamports, new_bytes, - &bpf_upgradable_id, + &bpf_upgradeable_id, true, ); test_program_replace_set_up_account( @@ -8602,13 +8303,17 @@ fn test_program_replace_does_not_exist_but_data_does_with_data() { &new_data, new_data_lamports, new_data_bytes.clone(), - &bpf_upgradable_id, + &bpf_upgradeable_id, false, ); let original_capitalization = bank.capitalization(); - bank.replace_program_account(&old, &new, "bank-apply_program_replacement"); + bank.replace_empty_account_with_upgradeable_program( + &old, + &new, + "bank-apply_program_replacement", + ); // Old program account was created and funded to pay for minimum rent // for the PDA @@ -8635,9 +8340,9 @@ fn test_program_replace_does_not_exist_but_data_does_with_data() { assert_eq!(old_data_account.data(), &new_data_bytes); // Ownership & executable match the new program accounts - assert_eq!(old_account.owner(), &bpf_upgradable_id); + assert_eq!(old_account.owner(), &bpf_upgradeable_id); assert!(old_account.executable()); - assert_eq!(old_data_account.owner(), &bpf_upgradable_id); + assert_eq!(old_data_account.owner(), &bpf_upgradeable_id); assert!(!old_data_account.executable()); // The remaining lamports from both program accounts minus the rent-exempt @@ -8651,296 +8356,6 @@ fn test_program_replace_does_not_exist_but_data_does_with_data() { ); } -#[test] -fn test_program_replace_upgradable_base_case() { - // Upgradable program - // - Old: PDA(OldData) - // - OldData: [Old program data] - // - New: PDA(NewData) - // - NewData: [*New program data] - // - // Should _only_ replace the data account, not the program account: - // - Old: PDA(OldData) - // - OldData: [*New program data] - let bpf_upgradable_id = bpf_loader_upgradeable::id(); - let mut bank = create_simple_test_bank(0); - - let old = Pubkey::new_unique(); - let (old_data, _) = Pubkey::find_program_address(&[old.as_ref()], &bpf_upgradable_id); - let old_bytes = old_data.to_bytes().to_vec(); - let old_lamports = bank.get_minimum_balance_for_rent_exemption(old_bytes.len()); - let old_data_bytes = vec![4; 10]; - let old_data_lamports = bank.get_minimum_balance_for_rent_exemption(old_data_bytes.len()); - test_program_replace_set_up_account( - &mut bank, - &old, - old_lamports, - old_bytes, - &bpf_upgradable_id, - true, - ); - test_program_replace_set_up_account( - &mut bank, - &old_data, - old_data_lamports, - old_data_bytes, - &bpf_upgradable_id, - false, - ); - - let new = Pubkey::new_unique(); - let (new_data, _) = Pubkey::find_program_address(&[new.as_ref()], &bpf_upgradable_id); - let new_bytes = new_data.to_bytes().to_vec(); - let new_lamports = bank.get_minimum_balance_for_rent_exemption(new_bytes.len()); - let new_data_bytes = vec![6; 30]; - let new_data_lamports = bank.get_minimum_balance_for_rent_exemption(new_data_bytes.len()); - test_program_replace_set_up_account( - &mut bank, - &new, - new_lamports, - new_bytes, - &bpf_upgradable_id, - true, - ); - test_program_replace_set_up_account( - &mut bank, - &new_data, - new_data_lamports, - new_data_bytes.clone(), - &bpf_upgradable_id, - false, - ); - - let original_capitalization = bank.capitalization(); - - bank.replace_program_account(&old, &new, "bank-apply_program_replacement"); - - // Old program account's balance was _not_ adjusted to pay for minimum rent - // for the PDA - // - // Note: In this test, the original bytes were unchanged (PDA) - assert_eq!(bank.get_balance(&old), old_lamports); - - // Old data account's balance is now the new data account's balance - assert_eq!(bank.get_balance(&old_data), new_data_lamports); - - // New program accounts are now empty - assert_eq!(bank.get_balance(&new), 0); - assert_eq!(bank.get_balance(&new_data), 0); - - // Old program account still holds the same PDA, ie: - // - Old: PDA(OldData) - let old_account = bank.get_account(&old).unwrap(); - assert_eq!(old_account.data(), &old_data.to_bytes().to_vec()); - - // Old data account now holds the new data, ie: - // - OldData: [*New program data] - let old_data_account = bank.get_account(&old_data).unwrap(); - assert_eq!(old_data_account.data(), &new_data_bytes); - - // Ownership & executable match the new program accounts - assert_eq!(old_account.owner(), &bpf_upgradable_id); - assert!(old_account.executable()); - assert_eq!(old_data_account.owner(), &bpf_upgradable_id); - assert!(!old_data_account.executable()); - - // Lamports from the new program account were burnt - // Lamports from the old data account were burnt - assert_eq!( - bank.capitalization(), - original_capitalization - new_lamports - old_data_lamports - ); -} - -#[test] -fn test_program_replace_upgradable_not_data_pda_at_first() { - // Upgradable program - // - Old: [*Old arbitrary data] (smaller than minimum rent-exempt size) - // - OldData: [Old program data] - // - New: PDA(NewData) - // - NewData: [*New program data] - // - // Should _only_ replace the data account, not the program account: - // - Old: PDA(OldData) - // - OldData: [*New program data] - let bpf_upgradable_id = bpf_loader_upgradeable::id(); - let mut bank = create_simple_test_bank(0); - - let old = Pubkey::new_unique(); - let (old_data, _) = Pubkey::find_program_address(&[old.as_ref()], &bpf_upgradable_id); - let old_bytes = vec![1; 18]; // Smaller than 32 bytes - let old_lamports = bank.get_minimum_balance_for_rent_exemption(old_bytes.len()); - let old_data_bytes = vec![4; 10]; - let old_data_lamports = bank.get_minimum_balance_for_rent_exemption(old_data_bytes.len()); - test_program_replace_set_up_account( - &mut bank, - &old, - old_lamports, - old_bytes, - &bpf_upgradable_id, - true, - ); - test_program_replace_set_up_account( - &mut bank, - &old_data, - old_data_lamports, - old_data_bytes, - &bpf_upgradable_id, - false, - ); - - let new = Pubkey::new_unique(); - let (new_data, _) = Pubkey::find_program_address(&[new.as_ref()], &bpf_upgradable_id); - let new_bytes = new_data.to_bytes().to_vec(); - let new_lamports = bank.get_minimum_balance_for_rent_exemption(new_bytes.len()); - let new_data_bytes = vec![6; 30]; - let new_data_lamports = bank.get_minimum_balance_for_rent_exemption(new_data_bytes.len()); - test_program_replace_set_up_account( - &mut bank, - &new, - new_lamports, - new_bytes, - &bpf_upgradable_id, - true, - ); - test_program_replace_set_up_account( - &mut bank, - &new_data, - new_data_lamports, - new_data_bytes.clone(), - &bpf_upgradable_id, - false, - ); - - let original_capitalization = bank.capitalization(); - - bank.replace_program_account(&old, &new, "bank-apply_program_replacement"); - - // Old program account's balance was adjusted to pay for minimum rent for - // the PDA (32 bytes) - // - // Note: In this test, the original lamports were _less_ than required - // rent for 32 bytes, so lamports were added - assert_eq!( - bank.get_balance(&old), - bank.get_minimum_balance_for_rent_exemption(old_data.to_bytes().len()) - ); - - // Old data account's balance is now the new data account's balance - assert_eq!(bank.get_balance(&old_data), new_data_lamports); - - // New program accounts are now empty - assert_eq!(bank.get_balance(&new), 0); - assert_eq!(bank.get_balance(&new_data), 0); - - // Old program account now holds the PDA, ie: - // - Old: PDA(OldData) - let old_account = bank.get_account(&old).unwrap(); - assert_eq!(old_account.data(), &old_data.to_bytes().to_vec()); - - // Old data account now holds the new data, ie: - // - OldData: [*New program data] - let old_data_account = bank.get_account(&old_data).unwrap(); - assert_eq!(old_data_account.data(), &new_data_bytes); - - // Ownership & executable match the new program accounts - assert_eq!(old_account.owner(), &bpf_upgradable_id); - assert!(old_account.executable()); - assert_eq!(old_data_account.owner(), &bpf_upgradable_id); - assert!(!old_data_account.executable()); - - // The remaining lamports from both program accounts minus the rent-exempt - // minimum were burnt - // Lamports from the old data account were burnt - let burnt_after_rent = new_lamports + old_lamports - - bank.get_minimum_balance_for_rent_exemption(old_data.to_bytes().len()); - assert_eq!( - bank.capitalization(), - original_capitalization - burnt_after_rent - old_data_lamports - ); -} - -#[test] -fn test_program_replace_upgradable_no_data_provided_with_replacement() { - // Upgradable program - // - Old: PDA(OldData) - // - OldData: [Old program data] - // - New: [*New program data] - // - // This is NOT allowed and should leave the program unchanged: - // - Old: PDA(OldData) - // - OldData: [Old program data] - let bpf_id = bpf_loader::id(); - let bpf_upgradable_id = bpf_loader_upgradeable::id(); - let mut bank = create_simple_test_bank(0); - - let old = Pubkey::new_unique(); - let (old_data, _) = Pubkey::find_program_address(&[old.as_ref()], &bpf_upgradable_id); - let old_bytes = vec![5; 5]; - let old_lamports = bank.get_minimum_balance_for_rent_exemption(old_bytes.len()); - let old_data_bytes = vec![4; 10]; - let old_data_lamports = bank.get_minimum_balance_for_rent_exemption(old_data_bytes.len()); - test_program_replace_set_up_account( - &mut bank, - &old, - old_lamports, - old_bytes.clone(), - &bpf_upgradable_id, - true, - ); - test_program_replace_set_up_account( - &mut bank, - &old_data, - old_data_lamports, - old_data_bytes.clone(), - &bpf_upgradable_id, - false, - ); - - let new = Pubkey::new_unique(); - let new_bytes = vec![2; 12]; - let new_lamports = bank.get_minimum_balance_for_rent_exemption(new_bytes.len()); - test_program_replace_set_up_account( - &mut bank, - &new, - new_lamports, - new_bytes.clone(), - &bpf_id, - true, - ); - - let original_capitalization = bank.capitalization(); - - bank.replace_program_account(&old, &new, "bank-apply_program_replacement"); - - // All balances are unchanged - assert_eq!(bank.get_balance(&old), old_lamports); - assert_eq!(bank.get_balance(&old_data), old_data_lamports); - assert_eq!(bank.get_balance(&new), new_lamports); - - // Old program accounts' data are unchanged - // - Old: PDA(OldData) - // - OldData: [Old program data] - let old_account = bank.get_account(&old).unwrap(); - assert_eq!(old_account.data(), &old_bytes); - let old_data_account = bank.get_account(&old_data).unwrap(); - assert_eq!(old_data_account.data(), &old_data_bytes); - - // New program account is unchanged - // - New: [*New program data] - let new_account = bank.get_account(&new).unwrap(); - assert_eq!(new_account.data(), &new_bytes); - - // Ownership & executable are unchanged - assert_eq!(old_account.owner(), &bpf_upgradable_id); - assert!(old_account.executable()); - assert_eq!(old_data_account.owner(), &bpf_upgradable_id); - assert!(!old_data_account.executable()); - - // Lamports were unchanged across the board - assert_eq!(bank.capitalization(), original_capitalization); -} - fn min_rent_exempt_balance_for_sysvars(bank: &Bank, sysvar_ids: &[Pubkey]) -> u64 { sysvar_ids .iter()