blocking.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. use anchor_client::solana_sdk::pubkey::Pubkey;
  2. use anchor_client::solana_sdk::signature::{Keypair, Signer};
  3. use anchor_client::solana_sdk::system_instruction;
  4. use anchor_client::{Client, Cluster};
  5. use anyhow::Result;
  6. use clap::Parser;
  7. use solana_sdk::commitment_config::CommitmentConfig;
  8. use solana_sdk::signature::read_keypair_file;
  9. use solana_sdk::system_program;
  10. // The `accounts` and `instructions` modules are generated by the framework.
  11. use basic_2::accounts as basic_2_accounts;
  12. use basic_2::instruction as basic_2_instruction;
  13. use basic_2::Counter;
  14. use events::instruction as events_instruction;
  15. use events::MyEvent;
  16. use optional::accounts::Initialize as OptionalInitialize;
  17. use optional::instruction as optional_instruction;
  18. // The `accounts` and `instructions` modules are generated by the framework.
  19. use basic_4::accounts as basic_4_accounts;
  20. use basic_4::instruction as basic_4_instruction;
  21. use basic_4::Counter as CounterAccount;
  22. // The `accounts` and `instructions` modules are generated by the framework.
  23. use crate::Opts;
  24. use composite::accounts::{Bar, CompositeUpdate, Foo, Initialize};
  25. use composite::instruction as composite_instruction;
  26. use composite::{DummyA, DummyB};
  27. use optional::account::{DataAccount, DataPda};
  28. use std::ops::Deref;
  29. use std::rc::Rc;
  30. use std::sync::Arc;
  31. use std::thread::sleep;
  32. use std::time::Duration;
  33. type TestFn<C> = &'static (dyn Fn(&Client<C>, Pubkey) -> Result<()> + Send + Sync);
  34. pub fn main() -> Result<()> {
  35. let opts = Opts::parse();
  36. // Wallet and cluster params.
  37. let payer = read_keypair_file(&*shellexpand::tilde("~/.config/solana/id.json"))
  38. .expect("Example requires a keypair file");
  39. let url = Cluster::Custom(
  40. "http://localhost:8899".to_string(),
  41. "ws://127.0.0.1:8900".to_string(),
  42. );
  43. if !opts.multithreaded {
  44. // Client.
  45. let payer = Rc::new(payer);
  46. let client =
  47. Client::new_with_options(url.clone(), payer.clone(), CommitmentConfig::processed());
  48. // Run tests on single thread with a single client using an Rc
  49. println!("\nStarting single thread test...");
  50. composite(&client, opts.composite_pid)?;
  51. basic_2(&client, opts.basic_2_pid)?;
  52. basic_4(&client, opts.basic_4_pid)?;
  53. // Can also use references, since they deref to a signer
  54. let payer: &Keypair = &payer;
  55. let client = Client::new_with_options(url, payer, CommitmentConfig::processed());
  56. events(&client, opts.events_pid)?;
  57. optional(&client, opts.optional_pid)?;
  58. } else {
  59. // Client.
  60. let payer = Arc::new(payer);
  61. let client = Client::new_with_options(url, payer, CommitmentConfig::processed());
  62. let client = Arc::new(client);
  63. // Run tests multithreaded while sharing a client
  64. println!("\nStarting multithread test...");
  65. let client = Arc::new(client);
  66. let tests: Vec<(TestFn<Arc<Keypair>>, Pubkey)> = vec![
  67. (&composite, opts.composite_pid),
  68. (&basic_2, opts.basic_2_pid),
  69. (&basic_4, opts.basic_4_pid),
  70. (&events, opts.events_pid),
  71. (&optional, opts.optional_pid),
  72. ];
  73. let mut handles = vec![];
  74. for (test, arg) in tests {
  75. let local_client = Arc::clone(&client);
  76. handles.push(std::thread::spawn(move || test(&local_client, arg)));
  77. }
  78. for handle in handles {
  79. assert!(handle.join().unwrap().is_ok());
  80. }
  81. }
  82. // Success.
  83. Ok(())
  84. }
  85. // Runs a client for examples/tutorial/composite.
  86. //
  87. // Make sure to run a localnet with the program deploy to run this example.
  88. pub fn composite<C: Deref<Target = impl Signer> + Clone>(
  89. client: &Client<C>,
  90. pid: Pubkey,
  91. ) -> Result<()> {
  92. // Program client.
  93. let program = client.program(pid)?;
  94. // `Initialize` parameters.
  95. let dummy_a = Keypair::new();
  96. let dummy_b = Keypair::new();
  97. // Build and send a transaction.
  98. program
  99. .request()
  100. .instruction(system_instruction::create_account(
  101. &program.payer(),
  102. &dummy_a.pubkey(),
  103. program.rpc().get_minimum_balance_for_rent_exemption(500)?,
  104. 500,
  105. &program.id(),
  106. ))
  107. .instruction(system_instruction::create_account(
  108. &program.payer(),
  109. &dummy_b.pubkey(),
  110. program.rpc().get_minimum_balance_for_rent_exemption(500)?,
  111. 500,
  112. &program.id(),
  113. ))
  114. .signer(&dummy_a)
  115. .signer(&dummy_b)
  116. .accounts(Initialize {
  117. dummy_a: dummy_a.pubkey(),
  118. dummy_b: dummy_b.pubkey(),
  119. })
  120. .args(composite_instruction::Initialize)
  121. .send()?;
  122. // Assert the transaction worked.
  123. let dummy_a_account: DummyA = program.account(dummy_a.pubkey())?;
  124. let dummy_b_account: DummyB = program.account(dummy_b.pubkey())?;
  125. assert_eq!(dummy_a_account.data, 0);
  126. assert_eq!(dummy_b_account.data, 0);
  127. // Build and send another transaction, using composite account parameters.
  128. program
  129. .request()
  130. .accounts(CompositeUpdate {
  131. foo: Foo {
  132. dummy_a: dummy_a.pubkey(),
  133. },
  134. bar: Bar {
  135. dummy_b: dummy_b.pubkey(),
  136. },
  137. })
  138. .args(composite_instruction::CompositeUpdate {
  139. dummy_a: 1234,
  140. dummy_b: 4321,
  141. })
  142. .send()?;
  143. // Assert the transaction worked.
  144. let dummy_a_account: DummyA = program.account(dummy_a.pubkey())?;
  145. let dummy_b_account: DummyB = program.account(dummy_b.pubkey())?;
  146. assert_eq!(dummy_a_account.data, 1234);
  147. assert_eq!(dummy_b_account.data, 4321);
  148. println!("Composite success!");
  149. Ok(())
  150. }
  151. // Runs a client for examples/tutorial/basic-2.
  152. //
  153. // Make sure to run a localnet with the program deploy to run this example.
  154. pub fn basic_2<C: Deref<Target = impl Signer> + Clone>(
  155. client: &Client<C>,
  156. pid: Pubkey,
  157. ) -> Result<()> {
  158. let program = client.program(pid)?;
  159. // `Create` parameters.
  160. let counter = Keypair::new();
  161. let authority = program.payer();
  162. // Build and send a transaction.
  163. program
  164. .request()
  165. .signer(&counter)
  166. .accounts(basic_2_accounts::Create {
  167. counter: counter.pubkey(),
  168. user: authority,
  169. system_program: system_program::ID,
  170. })
  171. .args(basic_2_instruction::Create { authority })
  172. .send()?;
  173. let counter_account: Counter = program.account(counter.pubkey())?;
  174. assert_eq!(counter_account.authority, authority);
  175. assert_eq!(counter_account.count, 0);
  176. println!("Basic 2 success!");
  177. Ok(())
  178. }
  179. pub fn events<C: Deref<Target = impl Signer> + Clone>(
  180. client: &Client<C>,
  181. pid: Pubkey,
  182. ) -> Result<()> {
  183. let program = client.program(pid)?;
  184. let (sender, receiver) = std::sync::mpsc::channel();
  185. let event_unsubscriber = program.on(move |_, event: MyEvent| {
  186. if sender.send(event).is_err() {
  187. println!("Error while transferring the event.")
  188. }
  189. })?;
  190. sleep(Duration::from_millis(1000));
  191. program
  192. .request()
  193. .args(events_instruction::Initialize {})
  194. .send()?;
  195. let event = receiver.recv().unwrap();
  196. assert_eq!(event.data, 5);
  197. assert_eq!(event.label, "hello".to_string());
  198. event_unsubscriber.unsubscribe();
  199. println!("Events success!");
  200. Ok(())
  201. }
  202. pub fn basic_4<C: Deref<Target = impl Signer> + Clone>(
  203. client: &Client<C>,
  204. pid: Pubkey,
  205. ) -> Result<()> {
  206. let program = client.program(pid)?;
  207. let authority = program.payer();
  208. let (counter, _) = Pubkey::find_program_address(&[b"counter"], &pid);
  209. program
  210. .request()
  211. .accounts(basic_4_accounts::Initialize {
  212. counter,
  213. authority,
  214. system_program: system_program::ID,
  215. })
  216. .args(basic_4_instruction::Initialize {})
  217. .send()?;
  218. let counter_account: CounterAccount = program.account(counter)?;
  219. assert_eq!(counter_account.authority, authority);
  220. assert_eq!(counter_account.count, 0);
  221. program
  222. .request()
  223. .accounts(basic_4_accounts::Increment { counter, authority })
  224. .args(basic_4_instruction::Increment {})
  225. .send()?;
  226. let counter_account: CounterAccount = program.account(counter)?;
  227. assert_eq!(counter_account.authority, authority);
  228. assert_eq!(counter_account.count, 1);
  229. println!("Basic 4 success!");
  230. Ok(())
  231. }
  232. // Runs a client for tests/optional.
  233. //
  234. // Make sure to run a localnet with the program deploy to run this example.
  235. pub fn optional<C: Deref<Target = impl Signer> + Clone>(
  236. client: &Client<C>,
  237. pid: Pubkey,
  238. ) -> Result<()> {
  239. // Program client.
  240. let program = client.program(pid)?;
  241. // `Initialize` parameters.
  242. let data_account_keypair = Keypair::new();
  243. let data_account_key = data_account_keypair.pubkey();
  244. let data_pda_seeds = &[DataPda::PREFIX.as_ref(), data_account_key.as_ref()];
  245. let data_pda_key = Pubkey::find_program_address(data_pda_seeds, &pid).0;
  246. let required_keypair = Keypair::new();
  247. let value: u64 = 10;
  248. // Build and send a transaction.
  249. program
  250. .request()
  251. .instruction(system_instruction::create_account(
  252. &program.payer(),
  253. &required_keypair.pubkey(),
  254. program
  255. .rpc()
  256. .get_minimum_balance_for_rent_exemption(DataAccount::LEN)?,
  257. DataAccount::LEN as u64,
  258. &program.id(),
  259. ))
  260. .signer(&data_account_keypair)
  261. .signer(&required_keypair)
  262. .accounts(OptionalInitialize {
  263. payer: Some(program.payer()),
  264. required: required_keypair.pubkey(),
  265. system_program: Some(system_program::id()),
  266. optional_account: Some(data_account_keypair.pubkey()),
  267. optional_pda: None,
  268. })
  269. .args(optional_instruction::Initialize { value, key: pid })
  270. .send()
  271. .unwrap();
  272. // Assert the transaction worked.
  273. let required: DataAccount = program.account(required_keypair.pubkey())?;
  274. assert_eq!(required.data, 0);
  275. let optional_pda = program.account::<DataPda>(data_pda_key);
  276. assert!(optional_pda.is_err());
  277. let optional_account: DataAccount = program.account(data_account_keypair.pubkey())?;
  278. assert_eq!(optional_account.data, value * 2);
  279. println!("Optional success!");
  280. Ok(())
  281. }