extend_program_ix.rs 29 KB

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