-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
nonblocking.rs
343 lines (291 loc) · 10.3 KB
/
nonblocking.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
use anchor_client::solana_sdk::pubkey::Pubkey;
use anchor_client::solana_sdk::signature::{Keypair, Signer};
use anchor_client::solana_sdk::system_instruction;
use anchor_client::{Client, Cluster};
use anyhow::Result;
use clap::Parser;
use solana_sdk::commitment_config::CommitmentConfig;
use solana_sdk::signature::read_keypair_file;
use solana_sdk::system_program;
// The `accounts` and `instructions` modules are generated by the framework.
use basic_2::accounts as basic_2_accounts;
use basic_2::instruction as basic_2_instruction;
use basic_2::Counter;
use events::instruction as events_instruction;
use events::MyEvent;
use optional::accounts::Initialize as OptionalInitialize;
use optional::instruction as optional_instruction;
// The `accounts` and `instructions` modules are generated by the framework.
use basic_4::accounts as basic_4_accounts;
use basic_4::instruction as basic_4_instruction;
use basic_4::Counter as CounterAccount;
// The `accounts` and `instructions` modules are generated by the framework.
use crate::Opts;
use composite::accounts::{Bar, CompositeUpdate, Foo, Initialize};
use composite::instruction as composite_instruction;
use composite::{DummyA, DummyB};
use optional::account::{DataAccount, DataPda};
use std::ops::Deref;
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::mpsc;
use tokio::time::sleep;
pub async fn main() -> Result<()> {
let opts = Opts::parse();
// Wallet and cluster params.
let payer = read_keypair_file(&*shellexpand::tilde("~/.config/solana/id.json"))
.expect("Example requires a keypair file");
let url = Cluster::Custom(
"http://localhost:8899".to_string(),
"ws://127.0.0.1:8900".to_string(),
);
// Client.
let payer = Arc::new(payer);
let client =
Client::new_with_options(url.clone(), payer.clone(), CommitmentConfig::processed());
println!("\nStarting async test...");
composite(&client, opts.composite_pid).await?;
basic_2(&client, opts.basic_2_pid).await?;
basic_4(&client, opts.basic_4_pid).await?;
test_tokio(client, opts.basic_2_pid).await?;
// Can also use references, since they deref to a signer
let payer: &Keypair = &payer;
let client = Client::new_with_options(url, payer, CommitmentConfig::processed());
events(&client, opts.events_pid).await?;
optional(&client, opts.optional_pid).await?;
// Success.
Ok(())
}
pub async fn test_tokio(client: Client<Arc<Keypair>>, pid: Pubkey) -> Result<()> {
tokio::spawn(async move {
let program = client.program(pid).unwrap();
// `Create` parameters.
let counter = Arc::new(Keypair::new());
let counter_pubkey = counter.pubkey();
let authority = program.payer();
// Build and send a transaction.
program
.request()
.signer(counter)
.accounts(basic_2_accounts::Create {
counter: counter_pubkey,
user: authority,
system_program: system_program::ID,
})
.args(basic_2_instruction::Create { authority })
.send()
.await
.unwrap();
let counter_account: Counter = program.account(counter_pubkey).await.unwrap();
assert_eq!(counter_account.authority, authority);
assert_eq!(counter_account.count, 0);
})
.await
.unwrap();
println!("Tokio success!");
Ok(())
}
pub async fn composite<C: Deref<Target = impl Signer> + Clone>(
client: &Client<C>,
pid: Pubkey,
) -> Result<()> {
// Program client.
let program = client.program(pid)?;
// `Initialize` parameters.
let dummy_a = Arc::new(Keypair::new());
let dummy_b = Arc::new(Keypair::new());
// Build and send a transaction.
program
.request()
.instruction(system_instruction::create_account(
&program.payer(),
&dummy_a.pubkey(),
program
.rpc()
.get_minimum_balance_for_rent_exemption(500)
.await?,
500,
&program.id(),
))
.instruction(system_instruction::create_account(
&program.payer(),
&dummy_b.pubkey(),
program
.rpc()
.get_minimum_balance_for_rent_exemption(500)
.await?,
500,
&program.id(),
))
.signer(dummy_a.clone())
.signer(dummy_b.clone())
.accounts(Initialize {
dummy_a: dummy_a.pubkey(),
dummy_b: dummy_b.pubkey(),
})
.args(composite_instruction::Initialize)
.send()
.await?;
// Assert the transaction worked.
let dummy_a_account: DummyA = program.account(dummy_a.pubkey()).await?;
let dummy_b_account: DummyB = program.account(dummy_b.pubkey()).await?;
assert_eq!(dummy_a_account.data, 0);
assert_eq!(dummy_b_account.data, 0);
// Build and send another transaction, using composite account parameters.
program
.request()
.accounts(CompositeUpdate {
foo: Foo {
dummy_a: dummy_a.pubkey(),
},
bar: Bar {
dummy_b: dummy_b.pubkey(),
},
})
.args(composite_instruction::CompositeUpdate {
dummy_a: 1234,
dummy_b: 4321,
})
.send()
.await?;
// Assert the transaction worked.
let dummy_a_account: DummyA = program.account(dummy_a.pubkey()).await?;
let dummy_b_account: DummyB = program.account(dummy_b.pubkey()).await?;
assert_eq!(dummy_a_account.data, 1234);
assert_eq!(dummy_b_account.data, 4321);
println!("Composite success!");
Ok(())
}
pub async fn basic_2<C: Deref<Target = impl Signer> + Clone>(
client: &Client<C>,
pid: Pubkey,
) -> Result<()> {
let program = client.program(pid)?;
// `Create` parameters.
let counter = Arc::new(Keypair::new());
let authority = program.payer();
// Build and send a transaction.
program
.request()
.signer(counter.clone())
.accounts(basic_2_accounts::Create {
counter: counter.pubkey(),
user: authority,
system_program: system_program::ID,
})
.args(basic_2_instruction::Create { authority })
.send()
.await?;
let counter_account: Counter = program.account(counter.pubkey()).await?;
assert_eq!(counter_account.authority, authority);
assert_eq!(counter_account.count, 0);
println!("Basic 2 success!");
Ok(())
}
pub async fn events<C: Deref<Target = impl Signer> + Clone>(
client: &Client<C>,
pid: Pubkey,
) -> Result<()> {
let program = client.program(pid)?;
let (sender, mut receiver) = mpsc::unbounded_channel();
let event_unsubscriber = program
.on(move |_, event: MyEvent| {
if sender.send(event).is_err() {
println!("Error while transferring the event.")
}
})
.await?;
sleep(Duration::from_millis(1000)).await;
program
.request()
.args(events_instruction::Initialize {})
.send()
.await?;
let event = receiver.recv().await.unwrap();
assert_eq!(event.data, 5);
assert_eq!(event.label, "hello".to_string());
event_unsubscriber.unsubscribe().await;
println!("Events success!");
Ok(())
}
pub async fn basic_4<C: Deref<Target = impl Signer> + Clone>(
client: &Client<C>,
pid: Pubkey,
) -> Result<()> {
let program = client.program(pid)?;
let authority = program.payer();
let (counter, _) = Pubkey::find_program_address(&[b"counter"], &pid);
program
.request()
.accounts(basic_4_accounts::Initialize {
counter,
authority,
system_program: system_program::ID,
})
.args(basic_4_instruction::Initialize {})
.send()
.await?;
let counter_account: CounterAccount = program.account(counter).await?;
assert_eq!(counter_account.authority, authority);
assert_eq!(counter_account.count, 0);
program
.request()
.accounts(basic_4_accounts::Increment { counter, authority })
.args(basic_4_instruction::Increment {})
.send()
.await?;
let counter_account: CounterAccount = program.account(counter).await?;
assert_eq!(counter_account.authority, authority);
assert_eq!(counter_account.count, 1);
println!("Basic 4 success!");
Ok(())
}
pub async fn optional<C: Deref<Target = impl Signer> + Clone>(
client: &Client<C>,
pid: Pubkey,
) -> Result<()> {
// Program client.
let program = client.program(pid)?;
// `Initialize` parameters.
let data_account_keypair = Arc::new(Keypair::new());
let data_account_key = data_account_keypair.pubkey();
let data_pda_seeds = &[DataPda::PREFIX.as_ref(), data_account_key.as_ref()];
let data_pda_key = Pubkey::find_program_address(data_pda_seeds, &pid).0;
let required_keypair = Arc::new(Keypair::new());
let value: u64 = 10;
// Build and send a transaction.
program
.request()
.instruction(system_instruction::create_account(
&program.payer(),
&required_keypair.pubkey(),
program
.rpc()
.get_minimum_balance_for_rent_exemption(DataAccount::LEN)
.await?,
DataAccount::LEN as u64,
&program.id(),
))
.signer(data_account_keypair.clone())
.signer(required_keypair.clone())
.accounts(OptionalInitialize {
payer: Some(program.payer()),
required: required_keypair.pubkey(),
system_program: Some(system_program::id()),
optional_account: Some(data_account_keypair.pubkey()),
optional_pda: None,
})
.args(optional_instruction::Initialize { value, key: pid })
.send()
.await
.unwrap();
// Assert the transaction worked.
let required: DataAccount = program.account(required_keypair.pubkey()).await?;
assert_eq!(required.data, 0);
let optional_pda = program.account::<DataPda>(data_pda_key).await;
assert!(optional_pda.is_err());
let optional_account: DataAccount = program.account(data_account_keypair.pubkey()).await?;
assert_eq!(optional_account.data, value * 2);
println!("Optional success!");
Ok(())
}