| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976 |
- use {
- assert_matches::assert_matches,
- common::{add_upgradeable_loader_account, assert_ix_error, setup_test_context},
- solana_account::{AccountSharedData, ReadableAccount, WritableAccount},
- solana_instruction::error::InstructionError,
- solana_keypair::Keypair,
- solana_loader_v3_interface::{
- instruction::extend_program_checked, state::UpgradeableLoaderState,
- },
- solana_program_test::*,
- solana_pubkey::Pubkey,
- solana_sdk_ids::bpf_loader_upgradeable::id,
- solana_signer::Signer,
- solana_system_interface::{
- error::SystemError, instruction as system_instruction, program as system_program,
- MAX_PERMITTED_DATA_LENGTH,
- },
- solana_transaction::Transaction,
- solana_transaction_error::TransactionError,
- };
- mod common;
- #[tokio::test]
- async fn test_extend_program() {
- let mut context = setup_test_context().await;
- let program_file = find_file("noop.so").expect("Failed to find the file");
- let data = read_file(program_file);
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
- let program_data_len = data.len() + programdata_data_offset;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority.pubkey()),
- },
- program_data_len,
- |account| account.data_as_mut_slice()[programdata_data_offset..].copy_from_slice(&data),
- )
- .await;
- let client = &mut context.banks_client;
- let payer = &context.payer;
- let recent_blockhash = context.last_blockhash;
- const ADDITIONAL_BYTES: u32 = 42;
- let transaction = Transaction::new_signed_with_payer(
- &[extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer.pubkey()),
- ADDITIONAL_BYTES,
- )],
- Some(&payer.pubkey()),
- &[payer, &upgrade_authority],
- recent_blockhash,
- );
- assert_matches!(client.process_transaction(transaction).await, Ok(()));
- let updated_program_data_account = client
- .get_account(programdata_address)
- .await
- .unwrap()
- .unwrap();
- assert_eq!(
- updated_program_data_account.data().len(),
- program_data_len + ADDITIONAL_BYTES as usize
- );
- }
- #[tokio::test]
- async fn test_failed_extend_twice_in_same_slot() {
- let mut context = setup_test_context().await;
- let program_file = find_file("noop.so").expect("Failed to find the file");
- let data = read_file(program_file);
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
- let program_data_len = data.len() + programdata_data_offset;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority.pubkey()),
- },
- program_data_len,
- |account| account.data_as_mut_slice()[programdata_data_offset..].copy_from_slice(&data),
- )
- .await;
- let client = &mut context.banks_client;
- let payer = &context.payer;
- let recent_blockhash = context.last_blockhash;
- const ADDITIONAL_BYTES: u32 = 42;
- let transaction = Transaction::new_signed_with_payer(
- &[extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer.pubkey()),
- ADDITIONAL_BYTES,
- )],
- Some(&payer.pubkey()),
- &[payer, &upgrade_authority],
- recent_blockhash,
- );
- assert_matches!(client.process_transaction(transaction).await, Ok(()));
- let updated_program_data_account = client
- .get_account(programdata_address)
- .await
- .unwrap()
- .unwrap();
- assert_eq!(
- updated_program_data_account.data().len(),
- program_data_len + ADDITIONAL_BYTES as usize
- );
- let recent_blockhash = client
- .get_new_latest_blockhash(&recent_blockhash)
- .await
- .unwrap();
- // Extending the program in the same slot should fail
- let transaction = Transaction::new_signed_with_payer(
- &[extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer.pubkey()),
- ADDITIONAL_BYTES,
- )],
- Some(&payer.pubkey()),
- &[payer, &upgrade_authority],
- recent_blockhash,
- );
- assert_matches!(
- client
- .process_transaction(transaction)
- .await
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::InvalidArgument)
- );
- }
- #[tokio::test]
- async fn test_failed_extend_upgrade_authority_did_not_sign() {
- let mut context = setup_test_context().await;
- let program_file = find_file("noop.so").expect("Failed to find the file");
- let data = read_file(program_file);
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
- let program_data_len = data.len() + programdata_data_offset;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority.pubkey()),
- },
- program_data_len,
- |account| account.data_as_mut_slice()[programdata_data_offset..].copy_from_slice(&data),
- )
- .await;
- let client = &mut context.banks_client;
- let payer = &context.payer;
- let recent_blockhash = context.last_blockhash;
- const ADDITIONAL_BYTES: u32 = 42;
- let transaction = Transaction::new_signed_with_payer(
- &[extend_program_checked(
- &program_address,
- &payer.pubkey(),
- Some(&payer.pubkey()),
- ADDITIONAL_BYTES,
- )],
- Some(&payer.pubkey()),
- &[payer],
- recent_blockhash,
- );
- assert_matches!(
- client
- .process_transaction(transaction)
- .await
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::IncorrectAuthority)
- );
- let mut ix = extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer.pubkey()),
- ADDITIONAL_BYTES,
- );
- ix.accounts[2].is_signer = false;
- let transaction = Transaction::new_signed_with_payer(
- &[ix],
- Some(&payer.pubkey()),
- &[payer],
- recent_blockhash,
- );
- assert_matches!(
- client
- .process_transaction(transaction)
- .await
- .unwrap_err()
- .unwrap(),
- TransactionError::InstructionError(0, InstructionError::MissingRequiredSignature)
- );
- }
- #[tokio::test]
- async fn test_extend_program_not_upgradeable() {
- let mut context = setup_test_context().await;
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: None,
- },
- 100,
- |_| {},
- )
- .await;
- let payer_address = context.payer.pubkey();
- assert_ix_error(
- &mut context,
- extend_program_checked(&program_address, &payer_address, Some(&payer_address), 42),
- None,
- InstructionError::Immutable,
- "should fail because the program data account isn't upgradeable",
- )
- .await;
- }
- #[tokio::test]
- async fn test_extend_program_by_zero_bytes() {
- let mut context = setup_test_context().await;
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority.pubkey()),
- },
- 100,
- |_| {},
- )
- .await;
- let payer_address = context.payer.pubkey();
- assert_ix_error(
- &mut context,
- extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer_address),
- 0,
- ),
- Some(&upgrade_authority),
- InstructionError::InvalidInstructionData,
- "should fail because the program data account must be extended by more than 0 bytes",
- )
- .await;
- }
- #[tokio::test]
- async fn test_extend_program_past_max_size() {
- let mut context = setup_test_context().await;
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority.pubkey()),
- },
- MAX_PERMITTED_DATA_LENGTH as usize,
- |_| {},
- )
- .await;
- let payer_address = context.payer.pubkey();
- assert_ix_error(
- &mut context,
- extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer_address),
- 1,
- ),
- Some(&upgrade_authority),
- InstructionError::InvalidRealloc,
- "should fail because the program data account cannot be extended past the max data size",
- )
- .await;
- }
- #[tokio::test]
- async fn test_extend_program_with_invalid_payer() {
- let mut context = setup_test_context().await;
- let rent = context.banks_client.get_rent().await.unwrap();
- let upgrade_authority_address = context.payer.pubkey();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority_address),
- },
- 100,
- |_| {},
- )
- .await;
- let payer_with_sufficient_funds = Keypair::new();
- context.set_account(
- &payer_with_sufficient_funds.pubkey(),
- &AccountSharedData::new(10_000_000_000, 0, &system_program::id()),
- );
- let payer_with_insufficient_funds = Keypair::new();
- context.set_account(
- &payer_with_insufficient_funds.pubkey(),
- &AccountSharedData::new(rent.minimum_balance(0), 0, &system_program::id()),
- );
- let payer_with_invalid_owner = Keypair::new();
- context.set_account(
- &payer_with_invalid_owner.pubkey(),
- &AccountSharedData::new(rent.minimum_balance(0), 0, &id()),
- );
- assert_ix_error(
- &mut context,
- extend_program_checked(
- &program_address,
- &upgrade_authority_address,
- Some(&payer_with_insufficient_funds.pubkey()),
- 1024,
- ),
- Some(&payer_with_insufficient_funds),
- InstructionError::from(SystemError::ResultWithNegativeLamports),
- "should fail because the payer has insufficient funds to cover program data account rent",
- )
- .await;
- assert_ix_error(
- &mut context,
- extend_program_checked(
- &program_address,
- &upgrade_authority_address,
- Some(&payer_with_invalid_owner.pubkey()),
- 1,
- ),
- Some(&payer_with_invalid_owner),
- InstructionError::ExternalAccountLamportSpend,
- "should fail because the payer is not a system account",
- )
- .await;
- let mut ix = extend_program_checked(
- &program_address,
- &upgrade_authority_address,
- Some(&payer_with_sufficient_funds.pubkey()),
- 1,
- );
- // Demote payer account meta to non-signer so that transaction signing succeeds
- {
- let payer_meta = ix
- .accounts
- .iter_mut()
- .find(|meta| meta.pubkey == payer_with_sufficient_funds.pubkey())
- .expect("expected to find payer account meta");
- payer_meta.is_signer = false;
- }
- assert_ix_error(
- &mut context,
- ix,
- None,
- InstructionError::PrivilegeEscalation,
- "should fail because the payer did not sign",
- )
- .await;
- }
- #[tokio::test]
- async fn test_extend_program_without_payer() {
- let mut context = setup_test_context().await;
- let rent = context.banks_client.get_rent().await.unwrap();
- let program_file = find_file("noop.so").expect("Failed to find the file");
- let data = read_file(program_file);
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
- let program_data_len = data.len() + programdata_data_offset;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority.pubkey()),
- },
- program_data_len,
- |account| account.data_as_mut_slice()[programdata_data_offset..].copy_from_slice(&data),
- )
- .await;
- assert_ix_error(
- &mut context,
- extend_program_checked(&program_address, &upgrade_authority.pubkey(), None, 1024),
- Some(&upgrade_authority),
- InstructionError::MissingAccount,
- "should fail because program data has insufficient funds to cover rent",
- )
- .await;
- let client = &mut context.banks_client;
- let payer = &context.payer;
- let recent_blockhash = context.last_blockhash;
- const ADDITIONAL_BYTES: u32 = 42;
- let min_balance_increase_for_extend = rent
- .minimum_balance(ADDITIONAL_BYTES as usize)
- .saturating_sub(rent.minimum_balance(0));
- let transaction = Transaction::new_signed_with_payer(
- &[
- system_instruction::transfer(
- &payer.pubkey(),
- &programdata_address,
- min_balance_increase_for_extend,
- ),
- extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- None,
- ADDITIONAL_BYTES,
- ),
- ],
- Some(&payer.pubkey()),
- &[payer, &upgrade_authority],
- recent_blockhash,
- );
- assert_matches!(client.process_transaction(transaction).await, Ok(()));
- let updated_program_data_account = client
- .get_account(programdata_address)
- .await
- .unwrap()
- .unwrap();
- assert_eq!(
- updated_program_data_account.data().len(),
- program_data_len + ADDITIONAL_BYTES as usize
- );
- }
- #[tokio::test]
- async fn test_extend_program_with_invalid_system_program() {
- let mut context = setup_test_context().await;
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- let program_data_len = 100;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority.pubkey()),
- },
- program_data_len,
- |_| {},
- )
- .await;
- let payer_address = context.payer.pubkey();
- let mut ix = extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer_address),
- 1,
- );
- // Change system program to an invalid key
- {
- let system_program_meta = ix
- .accounts
- .iter_mut()
- .find(|meta| meta.pubkey == crate::system_program::ID)
- .expect("expected to find system program account meta");
- system_program_meta.pubkey = Pubkey::new_unique();
- }
- assert_ix_error(
- &mut context,
- ix,
- Some(&upgrade_authority),
- InstructionError::MissingAccount,
- "should fail because the system program is missing",
- )
- .await;
- }
- #[tokio::test]
- async fn test_extend_program_with_mismatch_program_data() {
- let mut context = setup_test_context().await;
- let payer_address = context.payer.pubkey();
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- let mismatch_programdata_address = Pubkey::new_unique();
- add_upgradeable_loader_account(
- &mut context,
- &mismatch_programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority.pubkey()),
- },
- 100,
- |_| {},
- )
- .await;
- let mut ix = extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer_address),
- 1,
- );
- // Replace ProgramData account meta with invalid account
- {
- let program_data_meta = ix
- .accounts
- .iter_mut()
- .find(|meta| meta.pubkey == programdata_address)
- .expect("expected to find program data account meta");
- program_data_meta.pubkey = mismatch_programdata_address;
- }
- assert_ix_error(
- &mut context,
- ix,
- Some(&upgrade_authority),
- InstructionError::InvalidArgument,
- "should fail because the program data account doesn't match the program",
- )
- .await;
- }
- #[tokio::test]
- async fn test_extend_program_with_readonly_program_data() {
- let mut context = setup_test_context().await;
- let payer_address = context.payer.pubkey();
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority.pubkey()),
- },
- 100,
- |_| {},
- )
- .await;
- let mut ix = extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer_address),
- 1,
- );
- // Demote ProgramData account meta to read-only
- {
- let program_data_meta = ix
- .accounts
- .iter_mut()
- .find(|meta| meta.pubkey == programdata_address)
- .expect("expected to find program data account meta");
- program_data_meta.is_writable = false;
- }
- assert_ix_error(
- &mut context,
- ix,
- Some(&upgrade_authority),
- InstructionError::InvalidArgument,
- "should fail because the program data account is not writable",
- )
- .await;
- }
- #[tokio::test]
- async fn test_extend_program_with_invalid_program_data_state() {
- let mut context = setup_test_context().await;
- let payer_address = context.payer.pubkey();
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::Buffer {
- authority_address: Some(payer_address),
- },
- 100,
- |_| {},
- )
- .await;
- assert_ix_error(
- &mut context,
- extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer_address),
- 1024,
- ),
- Some(&upgrade_authority),
- InstructionError::InvalidAccountData,
- "should fail because the program data account state isn't valid",
- )
- .await;
- }
- #[tokio::test]
- async fn test_extend_program_with_invalid_program_data_owner() {
- let mut context = setup_test_context().await;
- let payer_address = context.payer.pubkey();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- let invalid_owner = Pubkey::new_unique();
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(payer_address),
- },
- 100,
- |account| account.set_owner(invalid_owner),
- )
- .await;
- assert_ix_error(
- &mut context,
- extend_program_checked(&program_address, &payer_address, Some(&payer_address), 1024),
- None,
- InstructionError::InvalidAccountOwner,
- "should fail because the program data account owner isn't valid",
- )
- .await;
- }
- #[tokio::test]
- async fn test_extend_program_with_readonly_program() {
- let mut context = setup_test_context().await;
- let payer_address = context.payer.pubkey();
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |_| {},
- )
- .await;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority.pubkey()),
- },
- 100,
- |_| {},
- )
- .await;
- let mut ix = extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer_address),
- 1,
- );
- // Demote Program account meta to read-only
- {
- let program_meta = ix
- .accounts
- .iter_mut()
- .find(|meta| meta.pubkey == program_address)
- .expect("expected to find program account meta");
- program_meta.is_writable = false;
- }
- assert_ix_error(
- &mut context,
- ix,
- Some(&upgrade_authority),
- InstructionError::InvalidArgument,
- "should fail because the program account is not writable",
- )
- .await;
- }
- #[tokio::test]
- async fn test_extend_program_with_invalid_program_owner() {
- let mut context = setup_test_context().await;
- let payer_address = context.payer.pubkey();
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- let invalid_owner = Pubkey::new_unique();
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Program {
- programdata_address,
- },
- UpgradeableLoaderState::size_of_program(),
- |account| account.set_owner(invalid_owner),
- )
- .await;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority.pubkey()),
- },
- 100,
- |_| {},
- )
- .await;
- assert_ix_error(
- &mut context,
- extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer_address),
- 1024,
- ),
- Some(&upgrade_authority),
- InstructionError::InvalidAccountOwner,
- "should fail because the program account owner isn't valid",
- )
- .await;
- }
- #[tokio::test]
- async fn test_extend_program_with_invalid_program_state() {
- let mut context = setup_test_context().await;
- let payer_address = context.payer.pubkey();
- let upgrade_authority = Keypair::new();
- let program_address = Pubkey::new_unique();
- let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
- add_upgradeable_loader_account(
- &mut context,
- &program_address,
- &UpgradeableLoaderState::Buffer {
- authority_address: Some(payer_address),
- },
- 100,
- |_| {},
- )
- .await;
- add_upgradeable_loader_account(
- &mut context,
- &programdata_address,
- &UpgradeableLoaderState::ProgramData {
- slot: 0,
- upgrade_authority_address: Some(upgrade_authority.pubkey()),
- },
- 100,
- |_| {},
- )
- .await;
- assert_ix_error(
- &mut context,
- extend_program_checked(
- &program_address,
- &upgrade_authority.pubkey(),
- Some(&payer_address),
- 1024,
- ),
- Some(&upgrade_authority),
- InstructionError::InvalidAccountData,
- "should fail because the program account state isn't valid",
- )
- .await;
- }
|