main.rs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. use anchor_client::solana_sdk::commitment_config::CommitmentConfig;
  2. use anchor_client::solana_sdk::pubkey::Pubkey;
  3. use anchor_client::solana_sdk::signature::read_keypair_file;
  4. use anchor_client::solana_sdk::signature::{Keypair, Signer};
  5. use anchor_client::solana_sdk::system_instruction;
  6. use anchor_client::{Client, Cluster, EventContext};
  7. use anyhow::Result;
  8. use solana_sdk::system_program;
  9. // The `accounts` and `instructions` modules are generated by the framework.
  10. use basic_2::accounts as basic_2_accounts;
  11. use basic_2::instruction as basic_2_instruction;
  12. use basic_2::Counter;
  13. use events::instruction as events_instruction;
  14. use events::MyEvent;
  15. use optional::accounts::Initialize as OptionalInitialize;
  16. use optional::instruction as optional_instruction;
  17. // The `accounts` and `instructions` modules are generated by the framework.
  18. use basic_4::accounts as basic_4_accounts;
  19. use basic_4::instruction as basic_4_instruction;
  20. use basic_4::Counter as CounterAccount;
  21. use clap::Parser;
  22. // The `accounts` and `instructions` modules are generated by the framework.
  23. use composite::accounts::{Bar, CompositeUpdate, Foo, Initialize};
  24. use composite::instruction as composite_instruction;
  25. use composite::{DummyA, DummyB};
  26. use optional::account::{DataAccount, DataPda};
  27. use std::rc::Rc;
  28. use std::time::Duration;
  29. #[derive(Parser, Debug)]
  30. pub struct Opts {
  31. #[clap(long)]
  32. composite_pid: Pubkey,
  33. #[clap(long)]
  34. basic_2_pid: Pubkey,
  35. #[clap(long)]
  36. basic_4_pid: Pubkey,
  37. #[clap(long)]
  38. events_pid: Pubkey,
  39. #[clap(long)]
  40. optional_pid: Pubkey,
  41. }
  42. // This example assumes a local validator is running with the programs
  43. // deployed at the addresses given by the CLI args.
  44. fn main() -> Result<()> {
  45. println!("Starting test...");
  46. let opts = Opts::parse();
  47. // Wallet and cluster params.
  48. let payer = read_keypair_file(&*shellexpand::tilde("~/.config/solana/id.json"))
  49. .expect("Example requires a keypair file");
  50. let url = Cluster::Custom(
  51. "http://localhost:8899".to_string(),
  52. "ws://127.0.0.1:8900".to_string(),
  53. );
  54. // Client.
  55. let client = Client::new_with_options(url, Rc::new(payer), CommitmentConfig::processed());
  56. // Run tests.
  57. composite(&client, opts.composite_pid)?;
  58. basic_2(&client, opts.basic_2_pid)?;
  59. basic_4(&client, opts.basic_4_pid)?;
  60. events(&client, opts.events_pid)?;
  61. optional(&client, opts.optional_pid)?;
  62. // Success.
  63. Ok(())
  64. }
  65. // Runs a client for examples/tutorial/composite.
  66. //
  67. // Make sure to run a localnet with the program deploy to run this example.
  68. fn composite(client: &Client, pid: Pubkey) -> Result<()> {
  69. // Program client.
  70. let program = client.program(pid);
  71. // `Initialize` parameters.
  72. let dummy_a = Keypair::new();
  73. let dummy_b = Keypair::new();
  74. // Build and send a transaction.
  75. program
  76. .request()
  77. .instruction(system_instruction::create_account(
  78. &program.payer(),
  79. &dummy_a.pubkey(),
  80. program.rpc().get_minimum_balance_for_rent_exemption(500)?,
  81. 500,
  82. &program.id(),
  83. ))
  84. .instruction(system_instruction::create_account(
  85. &program.payer(),
  86. &dummy_b.pubkey(),
  87. program.rpc().get_minimum_balance_for_rent_exemption(500)?,
  88. 500,
  89. &program.id(),
  90. ))
  91. .signer(&dummy_a)
  92. .signer(&dummy_b)
  93. .accounts(Initialize {
  94. dummy_a: dummy_a.pubkey(),
  95. dummy_b: dummy_b.pubkey(),
  96. })
  97. .args(composite_instruction::Initialize)
  98. .send()?;
  99. // Assert the transaction worked.
  100. let dummy_a_account: DummyA = program.account(dummy_a.pubkey())?;
  101. let dummy_b_account: DummyB = program.account(dummy_b.pubkey())?;
  102. assert_eq!(dummy_a_account.data, 0);
  103. assert_eq!(dummy_b_account.data, 0);
  104. // Build and send another transaction, using composite account parameters.
  105. program
  106. .request()
  107. .accounts(CompositeUpdate {
  108. foo: Foo {
  109. dummy_a: dummy_a.pubkey(),
  110. },
  111. bar: Bar {
  112. dummy_b: dummy_b.pubkey(),
  113. },
  114. })
  115. .args(composite_instruction::CompositeUpdate {
  116. dummy_a: 1234,
  117. dummy_b: 4321,
  118. })
  119. .send()?;
  120. // Assert the transaction worked.
  121. let dummy_a_account: DummyA = program.account(dummy_a.pubkey())?;
  122. let dummy_b_account: DummyB = program.account(dummy_b.pubkey())?;
  123. assert_eq!(dummy_a_account.data, 1234);
  124. assert_eq!(dummy_b_account.data, 4321);
  125. println!("Composite success!");
  126. Ok(())
  127. }
  128. // Runs a client for examples/tutorial/basic-2.
  129. //
  130. // Make sure to run a localnet with the program deploy to run this example.
  131. fn basic_2(client: &Client, pid: Pubkey) -> Result<()> {
  132. let program = client.program(pid);
  133. // `Create` parameters.
  134. let counter = Keypair::new();
  135. let authority = program.payer();
  136. // Build and send a transaction.
  137. program
  138. .request()
  139. .signer(&counter)
  140. .accounts(basic_2_accounts::Create {
  141. counter: counter.pubkey(),
  142. user: authority,
  143. system_program: system_program::ID,
  144. })
  145. .args(basic_2_instruction::Create { authority })
  146. .send()?;
  147. let counter_account: Counter = program.account(counter.pubkey())?;
  148. assert_eq!(counter_account.authority, authority);
  149. assert_eq!(counter_account.count, 0);
  150. println!("Basic 2 success!");
  151. Ok(())
  152. }
  153. fn events(client: &Client, pid: Pubkey) -> Result<()> {
  154. let program = client.program(pid);
  155. let (sender, receiver) = std::sync::mpsc::channel();
  156. let handle = program.on(move |_ctx: &EventContext, event: MyEvent| {
  157. sender.send(event).unwrap();
  158. })?;
  159. std::thread::sleep(Duration::from_millis(1000));
  160. program
  161. .request()
  162. .args(events_instruction::Initialize {})
  163. .send()?;
  164. let event = receiver.recv().unwrap();
  165. assert_eq!(event.data, 5);
  166. assert_eq!(event.label, "hello".to_string());
  167. // TODO: remove once https://github.com/solana-labs/solana/issues/16102
  168. // is addressed. Until then, drop the subscription handle in another
  169. // thread so that we deadlock in the other thread as to not block
  170. // this thread.
  171. std::thread::spawn(move || {
  172. drop(handle);
  173. });
  174. println!("Events success!");
  175. Ok(())
  176. }
  177. pub fn basic_4(client: &Client, pid: Pubkey) -> Result<()> {
  178. let program = client.program(pid);
  179. let authority = program.payer();
  180. let (counter, _) = Pubkey::find_program_address(&[b"counter"], &pid);
  181. program
  182. .request()
  183. .accounts(basic_4_accounts::Initialize {
  184. counter,
  185. authority,
  186. system_program: system_program::ID,
  187. })
  188. .args(basic_4_instruction::Initialize {})
  189. .send()?;
  190. let counter_account: CounterAccount = program.account(counter)?;
  191. assert_eq!(counter_account.authority, authority);
  192. assert_eq!(counter_account.count, 0);
  193. program
  194. .request()
  195. .accounts(basic_4_accounts::Increment { counter, authority })
  196. .args(basic_4_instruction::Increment {})
  197. .send()?;
  198. let counter_account: CounterAccount = program.account(counter)?;
  199. assert_eq!(counter_account.authority, authority);
  200. assert_eq!(counter_account.count, 1);
  201. println!("Basic 4 success!");
  202. Ok(())
  203. }
  204. // Runs a client for tests/optional.
  205. //
  206. // Make sure to run a localnet with the program deploy to run this example.
  207. fn optional(client: &Client, pid: Pubkey) -> Result<()> {
  208. // Program client.
  209. let program = client.program(pid);
  210. // `Initialize` parameters.
  211. let data_account_keypair = Keypair::new();
  212. let data_account_key = data_account_keypair.pubkey();
  213. let data_pda_seeds = &[DataPda::PREFIX.as_ref(), data_account_key.as_ref()];
  214. let data_pda_key = Pubkey::find_program_address(data_pda_seeds, &pid).0;
  215. let required_keypair = Keypair::new();
  216. let value: u64 = 10;
  217. // Build and send a transaction.
  218. program
  219. .request()
  220. .instruction(system_instruction::create_account(
  221. &program.payer(),
  222. &required_keypair.pubkey(),
  223. program
  224. .rpc()
  225. .get_minimum_balance_for_rent_exemption(DataAccount::LEN)?,
  226. DataAccount::LEN as u64,
  227. &program.id(),
  228. ))
  229. .signer(&data_account_keypair)
  230. .signer(&required_keypair)
  231. .accounts(OptionalInitialize {
  232. payer: Some(program.payer()),
  233. required: required_keypair.pubkey(),
  234. system_program: Some(system_program::id()),
  235. optional_account: Some(data_account_keypair.pubkey()),
  236. optional_pda: None,
  237. })
  238. .args(optional_instruction::Initialize { value, key: pid })
  239. .send()
  240. .unwrap();
  241. // Assert the transaction worked.
  242. let required: DataAccount = program.account(required_keypair.pubkey())?;
  243. assert_eq!(required.data, 0);
  244. let optional_pda = program.account::<DataPda>(data_pda_key);
  245. assert!(optional_pda.is_err());
  246. let optional_account: DataAccount = program.account(data_account_keypair.pubkey())?;
  247. assert_eq!(optional_account.data, value * 2);
  248. println!("Optional success!");
  249. Ok(())
  250. }