extend_program_ix.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
  1. use {
  2. assert_matches::assert_matches,
  3. common::{add_upgradeable_loader_account, assert_ix_error, setup_test_context},
  4. solana_program_test::*,
  5. solana_sdk::{
  6. account::{AccountSharedData, ReadableAccount, WritableAccount},
  7. bpf_loader_upgradeable::{extend_program, id, UpgradeableLoaderState},
  8. instruction::InstructionError,
  9. pubkey::Pubkey,
  10. signature::{Keypair, Signer},
  11. system_instruction::{self, SystemError, MAX_PERMITTED_DATA_LENGTH},
  12. system_program,
  13. transaction::{Transaction, TransactionError},
  14. },
  15. };
  16. mod common;
  17. #[tokio::test]
  18. async fn test_extend_program() {
  19. let mut context = setup_test_context().await;
  20. let program_file = find_file("noop.so").expect("Failed to find the file");
  21. let data = read_file(program_file);
  22. let program_address = Pubkey::new_unique();
  23. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  24. add_upgradeable_loader_account(
  25. &mut context,
  26. &program_address,
  27. &UpgradeableLoaderState::Program {
  28. programdata_address,
  29. },
  30. UpgradeableLoaderState::size_of_program(),
  31. |_| {},
  32. )
  33. .await;
  34. let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
  35. let program_data_len = data.len() + programdata_data_offset;
  36. add_upgradeable_loader_account(
  37. &mut context,
  38. &programdata_address,
  39. &UpgradeableLoaderState::ProgramData {
  40. slot: 0,
  41. upgrade_authority_address: Some(Pubkey::new_unique()),
  42. },
  43. program_data_len,
  44. |account| account.data_as_mut_slice()[programdata_data_offset..].copy_from_slice(&data),
  45. )
  46. .await;
  47. let client = &mut context.banks_client;
  48. let payer = &context.payer;
  49. let recent_blockhash = context.last_blockhash;
  50. const ADDITIONAL_BYTES: u32 = 42;
  51. let transaction = Transaction::new_signed_with_payer(
  52. &[extend_program(
  53. &program_address,
  54. Some(&payer.pubkey()),
  55. ADDITIONAL_BYTES,
  56. )],
  57. Some(&payer.pubkey()),
  58. &[payer],
  59. recent_blockhash,
  60. );
  61. assert_matches!(client.process_transaction(transaction).await, Ok(()));
  62. let updated_program_data_account = client
  63. .get_account(programdata_address)
  64. .await
  65. .unwrap()
  66. .unwrap();
  67. assert_eq!(
  68. updated_program_data_account.data().len(),
  69. program_data_len + ADDITIONAL_BYTES as usize
  70. );
  71. }
  72. #[tokio::test]
  73. async fn test_failed_extend_twice_in_same_slot() {
  74. let mut context = setup_test_context().await;
  75. let program_file = find_file("noop.so").expect("Failed to find the file");
  76. let data = read_file(program_file);
  77. let program_address = Pubkey::new_unique();
  78. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  79. add_upgradeable_loader_account(
  80. &mut context,
  81. &program_address,
  82. &UpgradeableLoaderState::Program {
  83. programdata_address,
  84. },
  85. UpgradeableLoaderState::size_of_program(),
  86. |_| {},
  87. )
  88. .await;
  89. let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
  90. let program_data_len = data.len() + programdata_data_offset;
  91. add_upgradeable_loader_account(
  92. &mut context,
  93. &programdata_address,
  94. &UpgradeableLoaderState::ProgramData {
  95. slot: 0,
  96. upgrade_authority_address: Some(Pubkey::new_unique()),
  97. },
  98. program_data_len,
  99. |account| account.data_as_mut_slice()[programdata_data_offset..].copy_from_slice(&data),
  100. )
  101. .await;
  102. let client = &mut context.banks_client;
  103. let payer = &context.payer;
  104. let recent_blockhash = context.last_blockhash;
  105. const ADDITIONAL_BYTES: u32 = 42;
  106. let transaction = Transaction::new_signed_with_payer(
  107. &[extend_program(
  108. &program_address,
  109. Some(&payer.pubkey()),
  110. ADDITIONAL_BYTES,
  111. )],
  112. Some(&payer.pubkey()),
  113. &[payer],
  114. recent_blockhash,
  115. );
  116. assert_matches!(client.process_transaction(transaction).await, Ok(()));
  117. let updated_program_data_account = client
  118. .get_account(programdata_address)
  119. .await
  120. .unwrap()
  121. .unwrap();
  122. assert_eq!(
  123. updated_program_data_account.data().len(),
  124. program_data_len + ADDITIONAL_BYTES as usize
  125. );
  126. let recent_blockhash = client
  127. .get_new_latest_blockhash(&recent_blockhash)
  128. .await
  129. .unwrap();
  130. // Extending the program in the same slot should fail
  131. let transaction = Transaction::new_signed_with_payer(
  132. &[extend_program(
  133. &program_address,
  134. Some(&payer.pubkey()),
  135. ADDITIONAL_BYTES,
  136. )],
  137. Some(&payer.pubkey()),
  138. &[payer],
  139. recent_blockhash,
  140. );
  141. assert_matches!(
  142. client
  143. .process_transaction(transaction)
  144. .await
  145. .unwrap_err()
  146. .unwrap(),
  147. TransactionError::InstructionError(0, InstructionError::InvalidArgument)
  148. );
  149. }
  150. #[tokio::test]
  151. async fn test_extend_program_not_upgradeable() {
  152. let mut context = setup_test_context().await;
  153. let program_address = Pubkey::new_unique();
  154. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  155. add_upgradeable_loader_account(
  156. &mut context,
  157. &program_address,
  158. &UpgradeableLoaderState::Program {
  159. programdata_address,
  160. },
  161. UpgradeableLoaderState::size_of_program(),
  162. |_| {},
  163. )
  164. .await;
  165. add_upgradeable_loader_account(
  166. &mut context,
  167. &programdata_address,
  168. &UpgradeableLoaderState::ProgramData {
  169. slot: 0,
  170. upgrade_authority_address: None,
  171. },
  172. 100,
  173. |_| {},
  174. )
  175. .await;
  176. let payer_address = context.payer.pubkey();
  177. assert_ix_error(
  178. &mut context,
  179. extend_program(&program_address, Some(&payer_address), 42),
  180. None,
  181. InstructionError::Immutable,
  182. "should fail because the program data account isn't upgradeable",
  183. )
  184. .await;
  185. }
  186. #[tokio::test]
  187. async fn test_extend_program_by_zero_bytes() {
  188. let mut context = setup_test_context().await;
  189. let program_address = Pubkey::new_unique();
  190. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  191. add_upgradeable_loader_account(
  192. &mut context,
  193. &program_address,
  194. &UpgradeableLoaderState::Program {
  195. programdata_address,
  196. },
  197. UpgradeableLoaderState::size_of_program(),
  198. |_| {},
  199. )
  200. .await;
  201. add_upgradeable_loader_account(
  202. &mut context,
  203. &programdata_address,
  204. &UpgradeableLoaderState::ProgramData {
  205. slot: 0,
  206. upgrade_authority_address: Some(Pubkey::new_unique()),
  207. },
  208. 100,
  209. |_| {},
  210. )
  211. .await;
  212. let payer_address = context.payer.pubkey();
  213. assert_ix_error(
  214. &mut context,
  215. extend_program(&program_address, Some(&payer_address), 0),
  216. None,
  217. InstructionError::InvalidInstructionData,
  218. "should fail because the program data account must be extended by more than 0 bytes",
  219. )
  220. .await;
  221. }
  222. #[tokio::test]
  223. async fn test_extend_program_past_max_size() {
  224. let mut context = setup_test_context().await;
  225. let program_address = Pubkey::new_unique();
  226. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  227. add_upgradeable_loader_account(
  228. &mut context,
  229. &program_address,
  230. &UpgradeableLoaderState::Program {
  231. programdata_address,
  232. },
  233. UpgradeableLoaderState::size_of_program(),
  234. |_| {},
  235. )
  236. .await;
  237. add_upgradeable_loader_account(
  238. &mut context,
  239. &programdata_address,
  240. &UpgradeableLoaderState::ProgramData {
  241. slot: 0,
  242. upgrade_authority_address: Some(Pubkey::new_unique()),
  243. },
  244. MAX_PERMITTED_DATA_LENGTH as usize,
  245. |_| {},
  246. )
  247. .await;
  248. let payer_address = context.payer.pubkey();
  249. assert_ix_error(
  250. &mut context,
  251. extend_program(&program_address, Some(&payer_address), 1),
  252. None,
  253. InstructionError::InvalidRealloc,
  254. "should fail because the program data account cannot be extended past the max data size",
  255. )
  256. .await;
  257. }
  258. #[tokio::test]
  259. async fn test_extend_program_with_invalid_payer() {
  260. let mut context = setup_test_context().await;
  261. let rent = context.banks_client.get_rent().await.unwrap();
  262. let program_address = Pubkey::new_unique();
  263. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  264. add_upgradeable_loader_account(
  265. &mut context,
  266. &program_address,
  267. &UpgradeableLoaderState::Program {
  268. programdata_address,
  269. },
  270. UpgradeableLoaderState::size_of_program(),
  271. |_| {},
  272. )
  273. .await;
  274. add_upgradeable_loader_account(
  275. &mut context,
  276. &programdata_address,
  277. &UpgradeableLoaderState::ProgramData {
  278. slot: 0,
  279. upgrade_authority_address: Some(Pubkey::new_unique()),
  280. },
  281. 100,
  282. |_| {},
  283. )
  284. .await;
  285. let payer_with_sufficient_funds = Keypair::new();
  286. context.set_account(
  287. &payer_with_sufficient_funds.pubkey(),
  288. &AccountSharedData::new(10_000_000_000, 0, &system_program::id()),
  289. );
  290. let payer_with_insufficient_funds = Keypair::new();
  291. context.set_account(
  292. &payer_with_insufficient_funds.pubkey(),
  293. &AccountSharedData::new(rent.minimum_balance(0), 0, &system_program::id()),
  294. );
  295. let payer_with_invalid_owner = Keypair::new();
  296. context.set_account(
  297. &payer_with_invalid_owner.pubkey(),
  298. &AccountSharedData::new(rent.minimum_balance(0), 0, &id()),
  299. );
  300. assert_ix_error(
  301. &mut context,
  302. extend_program(
  303. &program_address,
  304. Some(&payer_with_insufficient_funds.pubkey()),
  305. 1024,
  306. ),
  307. Some(&payer_with_insufficient_funds),
  308. InstructionError::from(SystemError::ResultWithNegativeLamports),
  309. "should fail because the payer has insufficient funds to cover program data account rent",
  310. )
  311. .await;
  312. assert_ix_error(
  313. &mut context,
  314. extend_program(
  315. &program_address,
  316. Some(&payer_with_invalid_owner.pubkey()),
  317. 1,
  318. ),
  319. Some(&payer_with_invalid_owner),
  320. InstructionError::ExternalAccountLamportSpend,
  321. "should fail because the payer is not a system account",
  322. )
  323. .await;
  324. let mut ix = extend_program(
  325. &program_address,
  326. Some(&payer_with_sufficient_funds.pubkey()),
  327. 1,
  328. );
  329. // Demote payer account meta to non-signer so that transaction signing succeeds
  330. {
  331. let payer_meta = ix
  332. .accounts
  333. .iter_mut()
  334. .find(|meta| meta.pubkey == payer_with_sufficient_funds.pubkey())
  335. .expect("expected to find payer account meta");
  336. payer_meta.is_signer = false;
  337. }
  338. assert_ix_error(
  339. &mut context,
  340. ix,
  341. None,
  342. InstructionError::PrivilegeEscalation,
  343. "should fail because the payer did not sign",
  344. )
  345. .await;
  346. }
  347. #[tokio::test]
  348. async fn test_extend_program_without_payer() {
  349. let mut context = setup_test_context().await;
  350. let rent = context.banks_client.get_rent().await.unwrap();
  351. let program_file = find_file("noop.so").expect("Failed to find the file");
  352. let data = read_file(program_file);
  353. let program_address = Pubkey::new_unique();
  354. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  355. add_upgradeable_loader_account(
  356. &mut context,
  357. &program_address,
  358. &UpgradeableLoaderState::Program {
  359. programdata_address,
  360. },
  361. UpgradeableLoaderState::size_of_program(),
  362. |_| {},
  363. )
  364. .await;
  365. let programdata_data_offset = UpgradeableLoaderState::size_of_programdata_metadata();
  366. let program_data_len = data.len() + programdata_data_offset;
  367. add_upgradeable_loader_account(
  368. &mut context,
  369. &programdata_address,
  370. &UpgradeableLoaderState::ProgramData {
  371. slot: 0,
  372. upgrade_authority_address: Some(Pubkey::new_unique()),
  373. },
  374. program_data_len,
  375. |account| account.data_as_mut_slice()[programdata_data_offset..].copy_from_slice(&data),
  376. )
  377. .await;
  378. assert_ix_error(
  379. &mut context,
  380. extend_program(&program_address, None, 1024),
  381. None,
  382. InstructionError::NotEnoughAccountKeys,
  383. "should fail because program data has insufficient funds to cover rent",
  384. )
  385. .await;
  386. let client = &mut context.banks_client;
  387. let payer = &context.payer;
  388. let recent_blockhash = context.last_blockhash;
  389. const ADDITIONAL_BYTES: u32 = 42;
  390. let min_balance_increase_for_extend = rent
  391. .minimum_balance(ADDITIONAL_BYTES as usize)
  392. .saturating_sub(rent.minimum_balance(0));
  393. let transaction = Transaction::new_signed_with_payer(
  394. &[
  395. system_instruction::transfer(
  396. &payer.pubkey(),
  397. &programdata_address,
  398. min_balance_increase_for_extend,
  399. ),
  400. extend_program(&program_address, None, ADDITIONAL_BYTES),
  401. ],
  402. Some(&payer.pubkey()),
  403. &[payer],
  404. recent_blockhash,
  405. );
  406. assert_matches!(client.process_transaction(transaction).await, Ok(()));
  407. let updated_program_data_account = client
  408. .get_account(programdata_address)
  409. .await
  410. .unwrap()
  411. .unwrap();
  412. assert_eq!(
  413. updated_program_data_account.data().len(),
  414. program_data_len + ADDITIONAL_BYTES as usize
  415. );
  416. }
  417. #[tokio::test]
  418. async fn test_extend_program_with_invalid_system_program() {
  419. let mut context = setup_test_context().await;
  420. let program_address = Pubkey::new_unique();
  421. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  422. add_upgradeable_loader_account(
  423. &mut context,
  424. &program_address,
  425. &UpgradeableLoaderState::Program {
  426. programdata_address,
  427. },
  428. UpgradeableLoaderState::size_of_program(),
  429. |_| {},
  430. )
  431. .await;
  432. let program_data_len = 100;
  433. add_upgradeable_loader_account(
  434. &mut context,
  435. &programdata_address,
  436. &UpgradeableLoaderState::ProgramData {
  437. slot: 0,
  438. upgrade_authority_address: Some(Pubkey::new_unique()),
  439. },
  440. program_data_len,
  441. |_| {},
  442. )
  443. .await;
  444. let payer_address = context.payer.pubkey();
  445. let mut ix = extend_program(&program_address, Some(&payer_address), 1);
  446. // Change system program to an invalid key
  447. {
  448. let system_program_meta = ix
  449. .accounts
  450. .iter_mut()
  451. .find(|meta| meta.pubkey == crate::system_program::ID)
  452. .expect("expected to find system program account meta");
  453. system_program_meta.pubkey = Pubkey::new_unique();
  454. }
  455. assert_ix_error(
  456. &mut context,
  457. ix,
  458. None,
  459. InstructionError::MissingAccount,
  460. "should fail because the system program is missing",
  461. )
  462. .await;
  463. }
  464. #[tokio::test]
  465. async fn test_extend_program_with_mismatch_program_data() {
  466. let mut context = setup_test_context().await;
  467. let payer_address = context.payer.pubkey();
  468. let program_address = Pubkey::new_unique();
  469. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  470. add_upgradeable_loader_account(
  471. &mut context,
  472. &program_address,
  473. &UpgradeableLoaderState::Program {
  474. programdata_address,
  475. },
  476. UpgradeableLoaderState::size_of_program(),
  477. |_| {},
  478. )
  479. .await;
  480. let mismatch_programdata_address = Pubkey::new_unique();
  481. add_upgradeable_loader_account(
  482. &mut context,
  483. &mismatch_programdata_address,
  484. &UpgradeableLoaderState::ProgramData {
  485. slot: 0,
  486. upgrade_authority_address: Some(Pubkey::new_unique()),
  487. },
  488. 100,
  489. |_| {},
  490. )
  491. .await;
  492. let mut ix = extend_program(&program_address, Some(&payer_address), 1);
  493. // Replace ProgramData account meta with invalid account
  494. {
  495. let program_data_meta = ix
  496. .accounts
  497. .iter_mut()
  498. .find(|meta| meta.pubkey == programdata_address)
  499. .expect("expected to find program data account meta");
  500. program_data_meta.pubkey = mismatch_programdata_address;
  501. }
  502. assert_ix_error(
  503. &mut context,
  504. ix,
  505. None,
  506. InstructionError::InvalidArgument,
  507. "should fail because the program data account doesn't match the program",
  508. )
  509. .await;
  510. }
  511. #[tokio::test]
  512. async fn test_extend_program_with_readonly_program_data() {
  513. let mut context = setup_test_context().await;
  514. let payer_address = context.payer.pubkey();
  515. let program_address = Pubkey::new_unique();
  516. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  517. add_upgradeable_loader_account(
  518. &mut context,
  519. &program_address,
  520. &UpgradeableLoaderState::Program {
  521. programdata_address,
  522. },
  523. UpgradeableLoaderState::size_of_program(),
  524. |_| {},
  525. )
  526. .await;
  527. add_upgradeable_loader_account(
  528. &mut context,
  529. &programdata_address,
  530. &UpgradeableLoaderState::ProgramData {
  531. slot: 0,
  532. upgrade_authority_address: Some(Pubkey::new_unique()),
  533. },
  534. 100,
  535. |_| {},
  536. )
  537. .await;
  538. let mut ix = extend_program(&program_address, Some(&payer_address), 1);
  539. // Demote ProgramData account meta to read-only
  540. {
  541. let program_data_meta = ix
  542. .accounts
  543. .iter_mut()
  544. .find(|meta| meta.pubkey == programdata_address)
  545. .expect("expected to find program data account meta");
  546. program_data_meta.is_writable = false;
  547. }
  548. assert_ix_error(
  549. &mut context,
  550. ix,
  551. None,
  552. InstructionError::InvalidArgument,
  553. "should fail because the program data account is not writable",
  554. )
  555. .await;
  556. }
  557. #[tokio::test]
  558. async fn test_extend_program_with_invalid_program_data_state() {
  559. let mut context = setup_test_context().await;
  560. let payer_address = context.payer.pubkey();
  561. let program_address = Pubkey::new_unique();
  562. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  563. add_upgradeable_loader_account(
  564. &mut context,
  565. &program_address,
  566. &UpgradeableLoaderState::Program {
  567. programdata_address,
  568. },
  569. UpgradeableLoaderState::size_of_program(),
  570. |_| {},
  571. )
  572. .await;
  573. add_upgradeable_loader_account(
  574. &mut context,
  575. &programdata_address,
  576. &UpgradeableLoaderState::Buffer {
  577. authority_address: Some(payer_address),
  578. },
  579. 100,
  580. |_| {},
  581. )
  582. .await;
  583. assert_ix_error(
  584. &mut context,
  585. extend_program(&program_address, Some(&payer_address), 1024),
  586. None,
  587. InstructionError::InvalidAccountData,
  588. "should fail because the program data account state isn't valid",
  589. )
  590. .await;
  591. }
  592. #[tokio::test]
  593. async fn test_extend_program_with_invalid_program_data_owner() {
  594. let mut context = setup_test_context().await;
  595. let payer_address = context.payer.pubkey();
  596. let program_address = Pubkey::new_unique();
  597. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  598. add_upgradeable_loader_account(
  599. &mut context,
  600. &program_address,
  601. &UpgradeableLoaderState::Program {
  602. programdata_address,
  603. },
  604. UpgradeableLoaderState::size_of_program(),
  605. |_| {},
  606. )
  607. .await;
  608. let invalid_owner = Pubkey::new_unique();
  609. add_upgradeable_loader_account(
  610. &mut context,
  611. &program_address,
  612. &UpgradeableLoaderState::ProgramData {
  613. slot: 0,
  614. upgrade_authority_address: Some(payer_address),
  615. },
  616. 100,
  617. |account| account.set_owner(invalid_owner),
  618. )
  619. .await;
  620. assert_ix_error(
  621. &mut context,
  622. extend_program(&program_address, Some(&payer_address), 1024),
  623. None,
  624. InstructionError::InvalidAccountOwner,
  625. "should fail because the program data account owner isn't valid",
  626. )
  627. .await;
  628. }
  629. #[tokio::test]
  630. async fn test_extend_program_with_readonly_program() {
  631. let mut context = setup_test_context().await;
  632. let payer_address = context.payer.pubkey();
  633. let program_address = Pubkey::new_unique();
  634. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  635. add_upgradeable_loader_account(
  636. &mut context,
  637. &program_address,
  638. &UpgradeableLoaderState::Program {
  639. programdata_address,
  640. },
  641. UpgradeableLoaderState::size_of_program(),
  642. |_| {},
  643. )
  644. .await;
  645. add_upgradeable_loader_account(
  646. &mut context,
  647. &programdata_address,
  648. &UpgradeableLoaderState::ProgramData {
  649. slot: 0,
  650. upgrade_authority_address: Some(Pubkey::new_unique()),
  651. },
  652. 100,
  653. |_| {},
  654. )
  655. .await;
  656. let mut ix = extend_program(&program_address, Some(&payer_address), 1);
  657. // Demote Program account meta to read-only
  658. {
  659. let program_meta = ix
  660. .accounts
  661. .iter_mut()
  662. .find(|meta| meta.pubkey == program_address)
  663. .expect("expected to find program account meta");
  664. program_meta.is_writable = false;
  665. }
  666. assert_ix_error(
  667. &mut context,
  668. ix,
  669. None,
  670. InstructionError::InvalidArgument,
  671. "should fail because the program account is not writable",
  672. )
  673. .await;
  674. }
  675. #[tokio::test]
  676. async fn test_extend_program_with_invalid_program_owner() {
  677. let mut context = setup_test_context().await;
  678. let payer_address = context.payer.pubkey();
  679. let program_address = Pubkey::new_unique();
  680. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  681. let invalid_owner = Pubkey::new_unique();
  682. add_upgradeable_loader_account(
  683. &mut context,
  684. &program_address,
  685. &UpgradeableLoaderState::Program {
  686. programdata_address,
  687. },
  688. UpgradeableLoaderState::size_of_program(),
  689. |account| account.set_owner(invalid_owner),
  690. )
  691. .await;
  692. add_upgradeable_loader_account(
  693. &mut context,
  694. &programdata_address,
  695. &UpgradeableLoaderState::ProgramData {
  696. slot: 0,
  697. upgrade_authority_address: Some(Pubkey::new_unique()),
  698. },
  699. 100,
  700. |_| {},
  701. )
  702. .await;
  703. assert_ix_error(
  704. &mut context,
  705. extend_program(&program_address, Some(&payer_address), 1024),
  706. None,
  707. InstructionError::InvalidAccountOwner,
  708. "should fail because the program account owner isn't valid",
  709. )
  710. .await;
  711. }
  712. #[tokio::test]
  713. async fn test_extend_program_with_invalid_program_state() {
  714. let mut context = setup_test_context().await;
  715. let payer_address = context.payer.pubkey();
  716. let program_address = Pubkey::new_unique();
  717. let (programdata_address, _) = Pubkey::find_program_address(&[program_address.as_ref()], &id());
  718. add_upgradeable_loader_account(
  719. &mut context,
  720. &program_address,
  721. &UpgradeableLoaderState::Buffer {
  722. authority_address: Some(payer_address),
  723. },
  724. 100,
  725. |_| {},
  726. )
  727. .await;
  728. add_upgradeable_loader_account(
  729. &mut context,
  730. &programdata_address,
  731. &UpgradeableLoaderState::ProgramData {
  732. slot: 0,
  733. upgrade_authority_address: Some(Pubkey::new_unique()),
  734. },
  735. 100,
  736. |_| {},
  737. )
  738. .await;
  739. assert_ix_error(
  740. &mut context,
  741. extend_program(&program_address, Some(&payer_address), 1024),
  742. None,
  743. InstructionError::InvalidAccountData,
  744. "should fail because the program account state isn't valid",
  745. )
  746. .await;
  747. }