diff --git a/Cargo.lock b/Cargo.lock index bb807a6584..5a134fd7ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3614,7 +3614,6 @@ dependencies = [ name = "solana-banks-client" version = "1.5.0" dependencies = [ - "async-trait", "bincode", "futures 0.3.5", "solana-banks-interface", diff --git a/banks-client/Cargo.toml b/banks-client/Cargo.toml index d779a71866..d524e22ce7 100644 --- a/banks-client/Cargo.toml +++ b/banks-client/Cargo.toml @@ -9,7 +9,6 @@ homepage = "https://solana.com/" edition = "2018" [dependencies] -async-trait = "0.1.36" bincode = "1.3.1" futures = "0.3" solana-banks-interface = { path = "../banks-interface", version = "1.5.0" } diff --git a/banks-client/src/lib.rs b/banks-client/src/lib.rs index f185badaa4..298637ef98 100644 --- a/banks-client/src/lib.rs +++ b/banks-client/src/lib.rs @@ -5,9 +5,8 @@ //! but they are undocumented, may change over time, and are generally more //! cumbersome to use. -use async_trait::async_trait; use futures::future::join_all; -pub use solana_banks_interface::{BanksClient, TransactionStatus}; +pub use solana_banks_interface::{BanksClient as TarpcClient, TransactionStatus}; use solana_banks_interface::{BanksRequest, BanksResponse}; use solana_sdk::{ account::{from_account, Account}, @@ -19,107 +18,118 @@ use solana_sdk::{ rent::Rent, signature::Signature, sysvar, - transaction::Transaction, + transaction::{self, Transaction}, transport, }; use std::io::{self, Error, ErrorKind}; use tarpc::{ - client, context, - rpc::{transport::channel::UnboundedChannel, ClientMessage, Response}, + client::{self, channel::RequestDispatch, NewClient}, + context::{self, Context}, + rpc::{ClientMessage, Response}, serde_transport::tcp, + Transport, }; use tokio::{net::ToSocketAddrs, time::Duration}; use tokio_serde::formats::Bincode; -#[async_trait] -pub trait BanksClientExt { +// This exists only for backward compatibility +pub trait BanksClientExt {} + +#[derive(Clone)] +pub struct BanksClient { + inner: TarpcClient, +} + +impl BanksClient { + #[allow(clippy::new_ret_no_self)] + pub fn new( + config: client::Config, + transport: C, + ) -> NewClient> + where + C: Transport, Response>, + { + TarpcClient::new(config, transport) + } + + pub async fn send_transaction_with_context( + &mut self, + ctx: Context, + transaction: Transaction, + ) -> io::Result<()> { + self.inner + .send_transaction_with_context(ctx, transaction) + .await + } + + pub async fn get_fees_with_commitment_and_context( + &mut self, + ctx: Context, + commitment: CommitmentLevel, + ) -> io::Result<(FeeCalculator, Hash, Slot)> { + self.inner + .get_fees_with_commitment_and_context(ctx, commitment) + .await + } + + pub async fn get_transaction_status_with_context( + &mut self, + ctx: Context, + signature: Signature, + ) -> io::Result> { + self.inner + .get_transaction_status_with_context(ctx, signature) + .await + } + + pub async fn get_slot_with_context( + &mut self, + ctx: Context, + commitment: CommitmentLevel, + ) -> io::Result { + self.inner.get_slot_with_context(ctx, commitment).await + } + + pub async fn process_transaction_with_commitment_and_context( + &mut self, + ctx: Context, + transaction: Transaction, + commitment: CommitmentLevel, + ) -> io::Result>> { + self.inner + .process_transaction_with_commitment_and_context(ctx, transaction, commitment) + .await + } + + pub async fn get_account_with_commitment_and_context( + &mut self, + ctx: Context, + address: Pubkey, + commitment: CommitmentLevel, + ) -> io::Result> { + self.inner + .get_account_with_commitment_and_context(ctx, address, commitment) + .await + } + /// Send a transaction and return immediately. The server will resend the /// transaction until either it is accepted by the cluster or the transaction's /// blockhash expires. - async fn send_transaction(&mut self, transaction: Transaction) -> io::Result<()>; - - /// Return a recent, rooted blockhash from the server. The cluster will only accept - /// transactions with a blockhash that has not yet expired. Use the `get_fees` - /// method to get both a blockhash and the blockhash's last valid slot. - async fn get_recent_blockhash(&mut self) -> io::Result; - - /// Return the fee parameters associated with a recent, rooted blockhash. The cluster - /// will use the transaction's blockhash to look up these same fee parameters and - /// use them to calculate the transaction fee. - async fn get_fees(&mut self) -> io::Result<(FeeCalculator, Hash, Slot)>; - - /// Return the cluster rent - async fn get_rent(&mut self) -> io::Result; - - /// Send a transaction and return after the transaction has been rejected or - /// reached the given level of commitment. - async fn process_transaction_with_commitment( - &mut self, - transaction: Transaction, - commitment: CommitmentLevel, - ) -> transport::Result<()>; - - /// Send a transaction and return after the transaction has been finalized or rejected. - async fn process_transaction(&mut self, transaction: Transaction) -> transport::Result<()>; - - /// Return the status of a transaction with a signature matching the transaction's first - /// signature. Return None if the transaction is not found, which may be because the - /// blockhash was expired or the fee-paying account had insufficient funds to pay the - /// transaction fee. Note that servers rarely store the full transaction history. This - /// method may return None if the transaction status has been discarded. - async fn get_transaction_status( - &mut self, - signature: Signature, - ) -> io::Result>; - - /// Same as get_transaction_status, but for multiple transactions. - async fn get_transaction_statuses( - &mut self, - signatures: Vec, - ) -> io::Result>>; - - /// Return the most recent rooted slot height. All transactions at or below this height - /// are said to be finalized. The cluster will not fork to a higher slot height. - async fn get_root_slot(&mut self) -> io::Result; - - /// Return the account at the given address at the slot corresponding to the given - /// commitment level. If the account is not found, None is returned. - async fn get_account_with_commitment( - &mut self, - address: Pubkey, - commitment: CommitmentLevel, - ) -> io::Result>; - - /// Return the account at the given address at the time of the most recent root slot. - /// If the account is not found, None is returned. - async fn get_account(&mut self, address: Pubkey) -> io::Result>; - - /// Return the balance in lamports of an account at the given address at the slot - /// corresponding to the given commitment level. - async fn get_balance_with_commitment( - &mut self, - address: Pubkey, - commitment: CommitmentLevel, - ) -> io::Result; - - /// Return the balance in lamports of an account at the given address at the time - /// of the most recent root slot. - async fn get_balance(&mut self, address: Pubkey) -> io::Result; -} - -#[async_trait] -impl BanksClientExt for BanksClient { - async fn send_transaction(&mut self, transaction: Transaction) -> io::Result<()> { + pub async fn send_transaction(&mut self, transaction: Transaction) -> io::Result<()> { self.send_transaction_with_context(context::current(), transaction) .await } - async fn get_fees(&mut self) -> io::Result<(FeeCalculator, Hash, Slot)> { + /// Return the fee parameters associated with a recent, rooted blockhash. The cluster + /// will use the transaction's blockhash to look up these same fee parameters and + /// use them to calculate the transaction fee. + pub async fn get_fees(&mut self) -> io::Result<(FeeCalculator, Hash, Slot)> { self.get_fees_with_commitment_and_context(context::current(), CommitmentLevel::Root) .await } - async fn get_rent(&mut self) -> io::Result { + /// Return the cluster rent + pub async fn get_rent(&mut self) -> io::Result { let rent_sysvar = self .get_account(sysvar::rent::id()) .await? @@ -130,11 +140,16 @@ impl BanksClientExt for BanksClient { }) } - async fn get_recent_blockhash(&mut self) -> io::Result { + /// Return a recent, rooted blockhash from the server. The cluster will only accept + /// transactions with a blockhash that has not yet expired. Use the `get_fees` + /// method to get both a blockhash and the blockhash's last valid slot. + pub async fn get_recent_blockhash(&mut self) -> io::Result { Ok(self.get_fees().await?.1) } - async fn process_transaction_with_commitment( + /// Send a transaction and return after the transaction has been rejected or + /// reached the given level of commitment. + pub async fn process_transaction_with_commitment( &mut self, transaction: Transaction, commitment: CommitmentLevel, @@ -150,17 +165,22 @@ impl BanksClientExt for BanksClient { } } - async fn process_transaction(&mut self, transaction: Transaction) -> transport::Result<()> { + /// Send a transaction and return after the transaction has been finalized or rejected. + pub async fn process_transaction(&mut self, transaction: Transaction) -> transport::Result<()> { self.process_transaction_with_commitment(transaction, CommitmentLevel::default()) .await } - async fn get_root_slot(&mut self) -> io::Result { + /// Return the most recent rooted slot height. All transactions at or below this height + /// are said to be finalized. The cluster will not fork to a higher slot height. + pub async fn get_root_slot(&mut self) -> io::Result { self.get_slot_with_context(context::current(), CommitmentLevel::Root) .await } - async fn get_account_with_commitment( + /// Return the account at the given address at the slot corresponding to the given + /// commitment level. If the account is not found, None is returned. + pub async fn get_account_with_commitment( &mut self, address: Pubkey, commitment: CommitmentLevel, @@ -169,12 +189,16 @@ impl BanksClientExt for BanksClient { .await } - async fn get_account(&mut self, address: Pubkey) -> io::Result> { + /// Return the account at the given address at the time of the most recent root slot. + /// If the account is not found, None is returned. + pub async fn get_account(&mut self, address: Pubkey) -> io::Result> { self.get_account_with_commitment(address, CommitmentLevel::default()) .await } - async fn get_balance_with_commitment( + /// Return the balance in lamports of an account at the given address at the slot + /// corresponding to the given commitment level. + pub async fn get_balance_with_commitment( &mut self, address: Pubkey, commitment: CommitmentLevel, @@ -185,12 +209,19 @@ impl BanksClientExt for BanksClient { Ok(account.map(|x| x.lamports).unwrap_or(0)) } - async fn get_balance(&mut self, address: Pubkey) -> io::Result { + /// Return the balance in lamports of an account at the given address at the time + /// of the most recent root slot. + pub async fn get_balance(&mut self, address: Pubkey) -> io::Result { self.get_balance_with_commitment(address, CommitmentLevel::default()) .await } - async fn get_transaction_status( + /// Return the status of a transaction with a signature matching the transaction's first + /// signature. Return None if the transaction is not found, which may be because the + /// blockhash was expired or the fee-paying account had insufficient funds to pay the + /// transaction fee. Note that servers rarely store the full transaction history. This + /// method may return None if the transaction status has been discarded. + pub async fn get_transaction_status( &mut self, signature: Signature, ) -> io::Result> { @@ -198,7 +229,8 @@ impl BanksClientExt for BanksClient { .await } - async fn get_transaction_statuses( + /// Same as get_transaction_status, but for multiple transactions. + pub async fn get_transaction_statuses( &mut self, signatures: Vec, ) -> io::Result>> { @@ -219,15 +251,20 @@ impl BanksClientExt for BanksClient { } } -pub async fn start_client( - transport: UnboundedChannel, ClientMessage>, -) -> io::Result { - BanksClient::new(client::Config::default(), transport).spawn() +pub async fn start_client(transport: C) -> io::Result +where + C: Transport, Response> + Send + 'static, +{ + Ok(BanksClient { + inner: TarpcClient::new(client::Config::default(), transport).spawn()?, + }) } pub async fn start_tcp_client(addr: T) -> io::Result { let transport = tcp::connect(addr, Bincode::default).await?; - BanksClient::new(client::Config::default(), transport).spawn() + Ok(BanksClient { + inner: TarpcClient::new(client::Config::default(), transport).spawn()?, + }) } #[cfg(test)] @@ -264,8 +301,7 @@ mod tests { Runtime::new()?.block_on(async { let client_transport = start_local_server(&bank_forks).await; - let mut banks_client = - BanksClient::new(client::Config::default(), client_transport).spawn()?; + let mut banks_client = start_client(client_transport).await?; let recent_blockhash = banks_client.get_recent_blockhash().await?; let transaction = Transaction::new(&[&genesis.mint_keypair], message, recent_blockhash); @@ -293,8 +329,7 @@ mod tests { Runtime::new()?.block_on(async { let client_transport = start_local_server(&bank_forks).await; - let mut banks_client = - BanksClient::new(client::Config::default(), client_transport).spawn()?; + let mut banks_client = start_client(client_transport).await?; let (_, recent_blockhash, last_valid_slot) = banks_client.get_fees().await?; let transaction = Transaction::new(&[&genesis.mint_keypair], message, recent_blockhash); let signature = transaction.signatures[0]; diff --git a/tokens/src/commands.rs b/tokens/src/commands.rs index efb7d36df6..0d4e7d10c1 100644 --- a/tokens/src/commands.rs +++ b/tokens/src/commands.rs @@ -7,7 +7,7 @@ use indexmap::IndexMap; use indicatif::{ProgressBar, ProgressStyle}; use pickledb::PickleDb; use serde::{Deserialize, Serialize}; -use solana_banks_client::{BanksClient, BanksClientExt}; +use solana_banks_client::BanksClient; use solana_sdk::{ commitment_config::CommitmentLevel, instruction::Instruction,