1use crate::bank::Bank;
2use gemachain_sdk::{
3 account::Account,
4 client::{AsyncClient, Client, SyncClient},
5 commitment_config::CommitmentConfig,
6 epoch_info::EpochInfo,
7 fee_calculator::{FeeCalculator, FeeRateGovernor},
8 hash::Hash,
9 instruction::Instruction,
10 message::{Message, SanitizedMessage},
11 pubkey::Pubkey,
12 signature::{Keypair, Signature, Signer},
13 signers::Signers,
14 system_instruction,
15 transaction::{self, Transaction},
16 transport::{Result, TransportError},
17};
18use std::{
19 convert::TryFrom,
20 io,
21 sync::{
22 mpsc::{channel, Receiver, Sender},
23 Arc, Mutex,
24 },
25 thread::{sleep, Builder},
26 time::{Duration, Instant},
27};
28
29pub struct BankClient {
30 bank: Arc<Bank>,
31 transaction_sender: Mutex<Sender<Transaction>>,
32}
33
34impl Client for BankClient {
35 fn tpu_addr(&self) -> String {
36 "Local BankClient".to_string()
37 }
38}
39
40impl AsyncClient for BankClient {
41 fn async_send_transaction(&self, transaction: Transaction) -> Result<Signature> {
42 let signature = transaction.signatures.get(0).cloned().unwrap_or_default();
43 let transaction_sender = self.transaction_sender.lock().unwrap();
44 transaction_sender.send(transaction).unwrap();
45 Ok(signature)
46 }
47
48 fn async_send_message<T: Signers>(
49 &self,
50 keypairs: &T,
51 message: Message,
52 recent_blockhash: Hash,
53 ) -> Result<Signature> {
54 let transaction = Transaction::new(keypairs, message, recent_blockhash);
55 self.async_send_transaction(transaction)
56 }
57
58 fn async_send_instruction(
59 &self,
60 keypair: &Keypair,
61 instruction: Instruction,
62 recent_blockhash: Hash,
63 ) -> Result<Signature> {
64 let message = Message::new(&[instruction], Some(&keypair.pubkey()));
65 self.async_send_message(&[keypair], message, recent_blockhash)
66 }
67
68 fn async_transfer(
70 &self,
71 carats: u64,
72 keypair: &Keypair,
73 pubkey: &Pubkey,
74 recent_blockhash: Hash,
75 ) -> Result<Signature> {
76 let transfer_instruction =
77 system_instruction::transfer(&keypair.pubkey(), pubkey, carats);
78 self.async_send_instruction(keypair, transfer_instruction, recent_blockhash)
79 }
80}
81
82impl SyncClient for BankClient {
83 fn send_and_confirm_message<T: Signers>(
84 &self,
85 keypairs: &T,
86 message: Message,
87 ) -> Result<Signature> {
88 let blockhash = self.bank.last_blockhash();
89 let transaction = Transaction::new(keypairs, message, blockhash);
90 self.bank.process_transaction(&transaction)?;
91 Ok(transaction.signatures.get(0).cloned().unwrap_or_default())
92 }
93
94 fn send_and_confirm_instruction(
96 &self,
97 keypair: &Keypair,
98 instruction: Instruction,
99 ) -> Result<Signature> {
100 let message = Message::new(&[instruction], Some(&keypair.pubkey()));
101 self.send_and_confirm_message(&[keypair], message)
102 }
103
104 fn transfer_and_confirm(
106 &self,
107 carats: u64,
108 keypair: &Keypair,
109 pubkey: &Pubkey,
110 ) -> Result<Signature> {
111 let transfer_instruction =
112 system_instruction::transfer(&keypair.pubkey(), pubkey, carats);
113 self.send_and_confirm_instruction(keypair, transfer_instruction)
114 }
115
116 fn get_account_data(&self, pubkey: &Pubkey) -> Result<Option<Vec<u8>>> {
117 Ok(self
118 .bank
119 .get_account(pubkey)
120 .map(|account| Account::from(account).data))
121 }
122
123 fn get_account(&self, pubkey: &Pubkey) -> Result<Option<Account>> {
124 Ok(self.bank.get_account(pubkey).map(Account::from))
125 }
126
127 fn get_account_with_commitment(
128 &self,
129 pubkey: &Pubkey,
130 _commitment_config: CommitmentConfig,
131 ) -> Result<Option<Account>> {
132 Ok(self.bank.get_account(pubkey).map(Account::from))
133 }
134
135 fn get_balance(&self, pubkey: &Pubkey) -> Result<u64> {
136 Ok(self.bank.get_balance(pubkey))
137 }
138
139 fn get_balance_with_commitment(
140 &self,
141 pubkey: &Pubkey,
142 _commitment_config: CommitmentConfig,
143 ) -> Result<u64> {
144 Ok(self.bank.get_balance(pubkey))
145 }
146
147 fn get_minimum_balance_for_rent_exemption(&self, data_len: usize) -> Result<u64> {
148 Ok(self.bank.get_minimum_balance_for_rent_exemption(data_len))
149 }
150
151 fn get_recent_blockhash(&self) -> Result<(Hash, FeeCalculator)> {
152 #[allow(deprecated)]
153 Ok(self.bank.last_blockhash_with_fee_calculator())
154 }
155
156 fn get_recent_blockhash_with_commitment(
157 &self,
158 _commitment_config: CommitmentConfig,
159 ) -> Result<(Hash, FeeCalculator, u64)> {
160 #[allow(deprecated)]
161 let (blockhash, fee_calculator) = self.bank.last_blockhash_with_fee_calculator();
162 #[allow(deprecated)]
163 let last_valid_slot = self
164 .bank
165 .get_blockhash_last_valid_slot(&blockhash)
166 .expect("bank blockhash queue should contain blockhash");
167 Ok((blockhash, fee_calculator, last_valid_slot))
168 }
169
170 fn get_fee_calculator_for_blockhash(&self, blockhash: &Hash) -> Result<Option<FeeCalculator>> {
171 #[allow(deprecated)]
172 Ok(self.bank.get_fee_calculator(blockhash))
173 }
174
175 fn get_fee_rate_governor(&self) -> Result<FeeRateGovernor> {
176 #[allow(deprecated)]
177 Ok(self.bank.get_fee_rate_governor().clone())
178 }
179
180 fn get_signature_status(
181 &self,
182 signature: &Signature,
183 ) -> Result<Option<transaction::Result<()>>> {
184 Ok(self.bank.get_signature_status(signature))
185 }
186
187 fn get_signature_status_with_commitment(
188 &self,
189 signature: &Signature,
190 _commitment_config: CommitmentConfig,
191 ) -> Result<Option<transaction::Result<()>>> {
192 Ok(self.bank.get_signature_status(signature))
193 }
194
195 fn get_slot(&self) -> Result<u64> {
196 Ok(self.bank.slot())
197 }
198
199 fn get_slot_with_commitment(&self, _commitment_config: CommitmentConfig) -> Result<u64> {
200 Ok(self.bank.slot())
201 }
202
203 fn get_transaction_count(&self) -> Result<u64> {
204 Ok(self.bank.transaction_count())
205 }
206
207 fn get_transaction_count_with_commitment(
208 &self,
209 _commitment_config: CommitmentConfig,
210 ) -> Result<u64> {
211 Ok(self.bank.transaction_count())
212 }
213
214 fn poll_for_signature_confirmation(
215 &self,
216 signature: &Signature,
217 min_confirmed_blocks: usize,
218 ) -> Result<usize> {
219 assert_eq!(min_confirmed_blocks, 1, "BankClient cannot observe the passage of multiple blocks, so min_confirmed_blocks must be 1");
221 let now = Instant::now();
222 let confirmed_blocks;
223 loop {
224 if self.bank.get_signature_status(signature).is_some() {
225 confirmed_blocks = 1;
226 break;
227 }
228 if now.elapsed().as_secs() > 15 {
229 return Err(TransportError::IoError(io::Error::new(
230 io::ErrorKind::Other,
231 format!(
232 "signature not found after {} seconds",
233 now.elapsed().as_secs()
234 ),
235 )));
236 }
237 sleep(Duration::from_millis(250));
238 }
239 Ok(confirmed_blocks)
240 }
241
242 fn poll_for_signature(&self, signature: &Signature) -> Result<()> {
243 let now = Instant::now();
244 loop {
245 let response = self.bank.get_signature_status(signature);
246 if let Some(res) = response {
247 if res.is_ok() {
248 break;
249 }
250 }
251 if now.elapsed().as_secs() > 15 {
252 return Err(TransportError::IoError(io::Error::new(
253 io::ErrorKind::Other,
254 format!(
255 "signature not found after {} seconds",
256 now.elapsed().as_secs()
257 ),
258 )));
259 }
260 sleep(Duration::from_millis(250));
261 }
262 Ok(())
263 }
264
265 fn get_new_blockhash(&self, blockhash: &Hash) -> Result<(Hash, FeeCalculator)> {
266 #[allow(deprecated)]
267 let (recent_blockhash, fee_calculator) = self.get_recent_blockhash()?;
268 if recent_blockhash != *blockhash {
269 Ok((recent_blockhash, fee_calculator))
270 } else {
271 Err(TransportError::IoError(io::Error::new(
272 io::ErrorKind::Other,
273 "Unable to get new blockhash",
274 )))
275 }
276 }
277
278 fn get_epoch_info(&self) -> Result<EpochInfo> {
279 Ok(self.bank.get_epoch_info())
280 }
281
282 fn get_latest_blockhash(&self) -> Result<Hash> {
283 Ok(self.bank.last_blockhash())
284 }
285
286 fn get_latest_blockhash_with_commitment(
287 &self,
288 _commitment_config: CommitmentConfig,
289 ) -> Result<(Hash, u64)> {
290 let blockhash = self.bank.last_blockhash();
291 let last_valid_block_height = self
292 .bank
293 .get_blockhash_last_valid_block_height(&blockhash)
294 .expect("bank blockhash queue should contain blockhash");
295 Ok((blockhash, last_valid_block_height))
296 }
297
298 fn is_blockhash_valid(
299 &self,
300 blockhash: &Hash,
301 _commitment_config: CommitmentConfig,
302 ) -> Result<bool> {
303 Ok(self.bank.is_blockhash_valid(blockhash))
304 }
305
306 fn get_fee_for_message(&self, blockhash: &Hash, message: &Message) -> Result<u64> {
307 SanitizedMessage::try_from(message.clone())
308 .ok()
309 .and_then(|message| self.bank.get_fee_for_message(blockhash, &message))
310 .ok_or_else(|| {
311 TransportError::IoError(io::Error::new(
312 io::ErrorKind::Other,
313 "Unable calculate fee",
314 ))
315 })
316 }
317
318 fn get_new_latest_blockhash(&self, blockhash: &Hash) -> Result<Hash> {
319 let latest_blockhash = self.get_latest_blockhash()?;
320 if latest_blockhash != *blockhash {
321 Ok(latest_blockhash)
322 } else {
323 Err(TransportError::IoError(io::Error::new(
324 io::ErrorKind::Other,
325 "Unable to get new blockhash",
326 )))
327 }
328 }
329}
330
331impl BankClient {
332 fn run(bank: &Bank, transaction_receiver: Receiver<Transaction>) {
333 while let Ok(tx) = transaction_receiver.recv() {
334 let mut transactions = vec![tx];
335 while let Ok(tx) = transaction_receiver.try_recv() {
336 transactions.push(tx);
337 }
338 let _ = bank.try_process_transactions(transactions.iter());
339 }
340 }
341
342 pub fn new_shared(bank: &Arc<Bank>) -> Self {
343 let (transaction_sender, transaction_receiver) = channel();
344 let transaction_sender = Mutex::new(transaction_sender);
345 let thread_bank = bank.clone();
346 let bank = bank.clone();
347 Builder::new()
348 .name("gemachain-bank-client".to_string())
349 .spawn(move || Self::run(&thread_bank, transaction_receiver))
350 .unwrap();
351 Self {
352 bank,
353 transaction_sender,
354 }
355 }
356
357 pub fn new(bank: Bank) -> Self {
358 Self::new_shared(&Arc::new(bank))
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use super::*;
365 use gemachain_sdk::{genesis_config::create_genesis_config, instruction::AccountMeta};
366
367 #[test]
368 fn test_bank_client_new_with_keypairs() {
369 let (genesis_config, john_doe_keypair) = create_genesis_config(10_000);
370 let john_pubkey = john_doe_keypair.pubkey();
371 let jane_doe_keypair = Keypair::new();
372 let jane_pubkey = jane_doe_keypair.pubkey();
373 let doe_keypairs = vec![&john_doe_keypair, &jane_doe_keypair];
374 let bank = Bank::new_for_tests(&genesis_config);
375 let bank_client = BankClient::new(bank);
376
377 let bob_pubkey = gemachain_sdk::pubkey::new_rand();
379 let mut transfer_instruction = system_instruction::transfer(&john_pubkey, &bob_pubkey, 42);
380 transfer_instruction
381 .accounts
382 .push(AccountMeta::new(jane_pubkey, true));
383
384 let message = Message::new(&[transfer_instruction], Some(&john_pubkey));
385 bank_client
386 .send_and_confirm_message(&doe_keypairs, message)
387 .unwrap();
388 assert_eq!(bank_client.get_balance(&bob_pubkey).unwrap(), 42);
389 }
390}