return_data.rs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. use {
  2. assert_matches::assert_matches,
  3. solana_account_info::{next_account_info, AccountInfo},
  4. solana_banks_client::BanksClientError,
  5. solana_commitment_config::CommitmentLevel,
  6. solana_instruction::{AccountMeta, Instruction},
  7. solana_msg::msg,
  8. solana_program_error::{ProgramError, ProgramResult},
  9. solana_program_test::{processor, ProgramTest},
  10. solana_pubkey::Pubkey,
  11. solana_sdk::program::{get_return_data, invoke, set_return_data},
  12. solana_signer::Signer,
  13. solana_transaction::Transaction,
  14. solana_transaction_context::TransactionReturnData,
  15. std::str::from_utf8,
  16. };
  17. // Process instruction to get return data from another program
  18. fn get_return_data_process_instruction(
  19. _program_id: &Pubkey,
  20. accounts: &[AccountInfo],
  21. input: &[u8],
  22. ) -> ProgramResult {
  23. msg!("Processing get_return_data instruction before CPI");
  24. let account_info_iter = &mut accounts.iter();
  25. let invoked_program_info = next_account_info(account_info_iter)?;
  26. invoke(
  27. &Instruction {
  28. program_id: *invoked_program_info.key,
  29. accounts: vec![],
  30. data: input.to_vec(),
  31. },
  32. &[invoked_program_info.clone()],
  33. )?;
  34. let return_data = get_return_data().unwrap();
  35. msg!("Processing get_return_data instruction after CPI");
  36. msg!("{}", from_utf8(&return_data.1).unwrap());
  37. assert_eq!(return_data.1, input.to_vec());
  38. Ok(())
  39. }
  40. // Process instruction to echo input back to another program
  41. fn set_return_data_process_instruction(
  42. _program_id: &Pubkey,
  43. _accounts: &[AccountInfo],
  44. input: &[u8],
  45. ) -> ProgramResult {
  46. msg!("Processing invoked instruction before set_return_data");
  47. set_return_data(input);
  48. msg!("Processing invoked instruction after set_return_data");
  49. Ok(())
  50. }
  51. #[tokio::test]
  52. async fn return_data() {
  53. let get_return_data_program_id = Pubkey::new_unique();
  54. let mut program_test = ProgramTest::new(
  55. "get_return_data",
  56. get_return_data_program_id,
  57. processor!(get_return_data_process_instruction),
  58. );
  59. let set_return_data_program_id = Pubkey::new_unique();
  60. program_test.add_program(
  61. "set_return_data",
  62. set_return_data_program_id,
  63. processor!(set_return_data_process_instruction),
  64. );
  65. let context = program_test.start_with_context().await;
  66. let instructions = vec![Instruction {
  67. program_id: get_return_data_program_id,
  68. accounts: vec![AccountMeta::new_readonly(set_return_data_program_id, false)],
  69. data: vec![240, 159, 166, 150],
  70. }];
  71. let transaction = Transaction::new_signed_with_payer(
  72. &instructions,
  73. Some(&context.payer.pubkey()),
  74. &[&context.payer],
  75. context.last_blockhash,
  76. );
  77. context
  78. .banks_client
  79. .process_transaction(transaction)
  80. .await
  81. .unwrap();
  82. }
  83. // Process instruction to echo input back to another program
  84. fn error_set_return_data_process_instruction(
  85. _program_id: &Pubkey,
  86. _accounts: &[AccountInfo],
  87. input: &[u8],
  88. ) -> ProgramResult {
  89. set_return_data(input);
  90. Err(ProgramError::InvalidInstructionData)
  91. }
  92. #[tokio::test]
  93. async fn simulation_return_data() {
  94. let error_set_return_data_program_id = Pubkey::new_unique();
  95. let program_test = ProgramTest::new(
  96. "error_set_return_data",
  97. error_set_return_data_program_id,
  98. processor!(error_set_return_data_process_instruction),
  99. );
  100. let context = program_test.start_with_context().await;
  101. let expected_data = vec![240, 159, 166, 150];
  102. let instructions = vec![Instruction {
  103. program_id: error_set_return_data_program_id,
  104. accounts: vec![],
  105. data: expected_data.clone(),
  106. }];
  107. let transaction = Transaction::new_signed_with_payer(
  108. &instructions,
  109. Some(&context.payer.pubkey()),
  110. &[&context.payer],
  111. context.last_blockhash,
  112. );
  113. let error = context
  114. .banks_client
  115. .process_transaction_with_preflight_and_commitment(transaction, CommitmentLevel::Confirmed)
  116. .await
  117. .unwrap_err();
  118. assert_matches!(
  119. error,
  120. BanksClientError::SimulationError {
  121. return_data: Some(TransactionReturnData {
  122. program_id,
  123. data,
  124. }),
  125. ..
  126. } if program_id == error_set_return_data_program_id && data == expected_data
  127. );
  128. }