From fbbc640958594bbcec4cb4decb2e5e30f203bea0 Mon Sep 17 00:00:00 2001 From: Tyera Eulberg Date: Mon, 30 Nov 2020 12:57:33 -0700 Subject: [PATCH] Revert solana-tokens to RpcClient (#13623) (#13863) * Revert solana-tokens to RpcClient * Fixup check_payer_balances tests * Use RpcClient::new_with_commitment in other tests * Sneak in helper fn from #13820 Co-authored-by: Tyera Eulberg Co-authored-by: Greg Fitzgerald --- Cargo.lock | 5 - tokens/Cargo.toml | 6 - tokens/src/commands.rs | 925 ++++++++++++++++++++------------------- tokens/src/db.rs | 5 +- tokens/src/main.rs | 25 +- tokens/src/spl_token.rs | 549 ++--------------------- tokens/tests/commands.rs | 9 +- 7 files changed, 503 insertions(+), 1021 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5b3ab62405..8b4369c817 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4948,14 +4948,11 @@ dependencies = [ "pickledb", "serde", "solana-account-decoder", - "solana-banks-client", - "solana-banks-server", "solana-clap-utils", "solana-cli-config", "solana-client", "solana-core", "solana-logger 1.4.14", - "solana-program-test", "solana-remote-wallet", "solana-runtime", "solana-sdk", @@ -4966,8 +4963,6 @@ dependencies = [ "spl-token", "tempfile", "thiserror", - "tokio 0.3.2", - "url 2.1.1", ] [[package]] diff --git a/tokens/Cargo.toml b/tokens/Cargo.toml index d7eb171c0e..6fea04252b 100644 --- a/tokens/Cargo.toml +++ b/tokens/Cargo.toml @@ -19,7 +19,6 @@ indicatif = "0.15.0" pickledb = "0.4.1" serde = { version = "1.0", features = ["derive"] } solana-account-decoder = { path = "../account-decoder", version = "1.4.14" } -solana-banks-client = { path = "../banks-client", version = "1.4.14" } solana-clap-utils = { path = "../clap-utils", version = "1.4.14" } solana-cli-config = { path = "../cli-config", version = "1.4.14" } solana-client = { path = "../client", version = "1.4.14" } @@ -33,13 +32,8 @@ spl-associated-token-account-v1-0 = { package = "spl-associated-token-account", spl-token-v2-0 = { package = "spl-token", version = "=3.0.0", features = ["no-entrypoint"] } tempfile = "3.1.0" thiserror = "1.0" -tokio = { version = "0.3", features = ["full"] } -url = "2.1" [dev-dependencies] bincode = "1.3.1" -solana-banks-server = { path = "../banks-server", version = "1.4.14" } solana-core = { path = "../core", version = "1.4.14" } solana-logger = { path = "../logger", version = "1.4.14" } -solana-program-test = { path = "../program-test", version = "1.4.14" } -solana-runtime = { path = "../runtime", version = "1.4.14" } diff --git a/tokens/src/commands.rs b/tokens/src/commands.rs index 0aba708dae..dd73e34f8b 100644 --- a/tokens/src/commands.rs +++ b/tokens/src/commands.rs @@ -14,16 +14,19 @@ use serde::{Deserialize, Serialize}; use solana_account_decoder::parse_token::{ pubkey_from_spl_token_v2_0, spl_token_v2_0_pubkey, token_amount_to_ui_amount, }; -use solana_banks_client::{BanksClient, BanksClientExt}; +use solana_client::{ + client_error::{ClientError, Result as ClientResult}, + rpc_client::RpcClient, + rpc_config::RpcSendTransactionConfig, +}; use solana_sdk::{ - commitment_config::CommitmentLevel, + commitment_config::CommitmentConfig, instruction::Instruction, message::Message, native_token::{lamports_to_sol, sol_to_lamports}, signature::{unique_signers, Signature, Signer}, system_instruction, transaction::Transaction, - transport::{self, TransportError}, }; use solana_stake_program::{ stake_instruction::{self, LockupArgs}, @@ -34,9 +37,9 @@ use spl_token_v2_0::solana_program::program_error::ProgramError; use std::{ cmp::{self}, io, + thread::sleep, time::Duration, }; -use tokio::time::sleep; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] pub struct Allocation { @@ -88,7 +91,7 @@ pub enum Error { #[error("PickleDb error")] PickleDbError(#[from] pickledb::error::Error), #[error("Transport error")] - TransportError(#[from] TransportError), + ClientError(#[from] ClientError), #[error("Missing lockup authority")] MissingLockupAuthority, #[error("insufficient funds in {0:?}, requires {1} SOL")] @@ -140,16 +143,16 @@ fn apply_previous_transactions( allocations.retain(|x| x.amount > 0); } -async fn transfer( - client: &mut BanksClient, +fn transfer( + client: &RpcClient, lamports: u64, sender_keypair: &S, to_pubkey: &Pubkey, -) -> io::Result { +) -> ClientResult { let create_instruction = system_instruction::transfer(&sender_keypair.pubkey(), &to_pubkey, lamports); let message = Message::new(&[create_instruction], Some(&sender_keypair.pubkey())); - let recent_blockhash = client.get_recent_blockhash().await?; + let (recent_blockhash, _fees) = client.get_recent_blockhash()?; Ok(Transaction::new( &[sender_keypair], message, @@ -235,8 +238,8 @@ fn distribution_instructions( instructions } -async fn distribute_allocations( - client: &mut BanksClient, +fn distribute_allocations( + client: &RpcClient, db: &mut PickleDb, allocations: &[Allocation], args: &DistributeTokensArgs, @@ -260,10 +263,11 @@ async fn distribute_allocations( &wallet_address, &spl_token_v2_0_pubkey(&spl_token_args.mint), ); - let do_create_associated_token_account = client - .get_account(pubkey_from_spl_token_v2_0(&associated_token_address)) - .await? - .is_none(); + let do_create_associated_token_account = + client.get_multiple_accounts(&[pubkey_from_spl_token_v2_0( + &associated_token_address, + )])?[0] + .is_none(); if do_create_associated_token_account { created_accounts += 1; } @@ -297,10 +301,9 @@ async fn distribute_allocations( .map(|message| message.header.num_required_signatures as usize) .sum(); if args.spl_token_args.is_some() { - check_spl_token_balances(num_signatures, allocations, client, args, created_accounts) - .await?; + check_spl_token_balances(num_signatures, allocations, client, args, created_accounts)?; } else { - check_payer_balances(num_signatures, allocations, client, args).await?; + check_payer_balances(num_signatures, allocations, client, args)?; } for ((allocation, message), (new_stake_account_keypair, lockup_date)) in @@ -322,13 +325,19 @@ async fn distribute_allocations( } } let signers = unique_signers(signers); - let result: transport::Result<(Transaction, u64)> = { + let result: ClientResult<(Transaction, u64)> = { if args.dry_run { Ok((Transaction::new_unsigned(message), std::u64::MAX)) } else { - let (_fee_calculator, blockhash, last_valid_slot) = client.get_fees().await?; + let (blockhash, _fee_calculator, last_valid_slot) = client + .get_recent_blockhash_with_commitment(CommitmentConfig::default())? + .value; let transaction = Transaction::new(&signers, message, blockhash); - client.send_transaction(transaction.clone()).await?; + let config = RpcSendTransactionConfig { + skip_preflight: true, + ..RpcSendTransactionConfig::default() + }; + client.send_transaction_with_config(&transaction, config)?; Ok((transaction, last_valid_slot)) } }; @@ -424,8 +433,8 @@ fn new_spinner_progress_bar() -> ProgressBar { progress_bar } -pub async fn process_allocations( - client: &mut BanksClient, +pub fn process_allocations( + client: &RpcClient, args: &DistributeTokensArgs, ) -> Result, Error> { let require_lockup_heading = args.stake_args.is_some(); @@ -451,7 +460,7 @@ pub async fn process_allocations( let mut db = db::open_db(&args.transaction_db, args.dry_run)?; // Start by finalizing any transactions from the previous run. - let confirmations = finalize_transactions(client, &mut db, args.dry_run).await?; + let confirmations = finalize_transactions(client, &mut db, args.dry_run)?; let transaction_infos = db::read_transaction_infos(&db); apply_previous_transactions(&mut allocations, &transaction_infos); @@ -492,9 +501,9 @@ pub async fn process_allocations( style(format!("{:<44} {:>24}", "Recipient", "Expected Balance",)).bold() ); - distribute_allocations(client, &mut db, &allocations, args).await?; + distribute_allocations(client, &mut db, &allocations, args)?; - let opt_confirmations = finalize_transactions(client, &mut db, args.dry_run).await?; + let opt_confirmations = finalize_transactions(client, &mut db, args.dry_run)?; if !args.dry_run { if let Some(output_path) = &args.output_path { @@ -505,8 +514,8 @@ pub async fn process_allocations( Ok(opt_confirmations) } -async fn finalize_transactions( - client: &mut BanksClient, +fn finalize_transactions( + client: &RpcClient, db: &mut PickleDb, dry_run: bool, ) -> Result, Error> { @@ -514,7 +523,7 @@ async fn finalize_transactions( return Ok(None); } - let mut opt_confirmations = update_finalized_transactions(client, db).await?; + let mut opt_confirmations = update_finalized_transactions(client, db)?; let progress_bar = new_spinner_progress_bar(); @@ -527,8 +536,8 @@ async fn finalize_transactions( } // Sleep for about 1 slot - sleep(Duration::from_millis(500)).await; - let opt_conf = update_finalized_transactions(client, db).await?; + sleep(Duration::from_millis(500)); + let opt_conf = update_finalized_transactions(client, db)?; opt_confirmations = opt_conf; } @@ -537,8 +546,8 @@ async fn finalize_transactions( // Update the finalized bit on any transactions that are now rooted // Return the lowest number of confirmations on the unfinalized transactions or None if all are finalized. -async fn update_finalized_transactions( - client: &mut BanksClient, +fn update_finalized_transactions( + client: &RpcClient, db: &mut PickleDb, ) -> Result, Error> { let transaction_infos = db::read_transaction_infos(db); @@ -558,9 +567,9 @@ async fn update_finalized_transactions( .filter(|sig| *sig != Signature::default()) // Filter out dry-run signatures .collect(); let transaction_statuses = client - .get_transaction_statuses(unconfirmed_signatures) - .await?; - let root_slot = client.get_root_slot().await?; + .get_signature_statuses(&unconfirmed_signatures)? + .value; + let root_slot = client.get_slot()?; let mut confirmations = None; for ((transaction, last_valid_slot), opt_transaction_status) in unconfirmed_transactions @@ -585,15 +594,15 @@ async fn update_finalized_transactions( Ok(confirmations) } -async fn check_payer_balances( +fn check_payer_balances( num_signatures: usize, allocations: &[Allocation], - client: &mut BanksClient, + client: &RpcClient, args: &DistributeTokensArgs, ) -> Result<(), Error> { let mut undistributed_tokens: u64 = allocations.iter().map(|x| x.amount).sum(); - let (fee_calculator, _blockhash, _last_valid_slot) = client.get_fees().await?; + let (_blockhash, fee_calculator) = client.get_recent_blockhash()?; let fees = fee_calculator .lamports_per_signature .checked_mul(num_signatures as u64) @@ -611,7 +620,7 @@ async fn check_payer_balances( }; if let Some((unlocked_sol_source, total_unlocked_sol)) = unlocked_sol_source { - let staker_balance = client.get_balance(distribution_source).await?; + let staker_balance = client.get_balance(&distribution_source)?; if staker_balance < undistributed_tokens { return Err(Error::InsufficientFunds( vec![FundingSource::StakeAccount].into(), @@ -619,7 +628,7 @@ async fn check_payer_balances( )); } if args.fee_payer.pubkey() == unlocked_sol_source { - let balance = client.get_balance(args.fee_payer.pubkey()).await?; + let balance = client.get_balance(&args.fee_payer.pubkey())?; if balance < fees + total_unlocked_sol { return Err(Error::InsufficientFunds( vec![FundingSource::SystemAccount, FundingSource::FeePayer].into(), @@ -627,14 +636,14 @@ async fn check_payer_balances( )); } } else { - let fee_payer_balance = client.get_balance(args.fee_payer.pubkey()).await?; + let fee_payer_balance = client.get_balance(&args.fee_payer.pubkey())?; if fee_payer_balance < fees { return Err(Error::InsufficientFunds( vec![FundingSource::FeePayer].into(), lamports_to_sol(fees), )); } - let unlocked_sol_balance = client.get_balance(unlocked_sol_source).await?; + let unlocked_sol_balance = client.get_balance(&unlocked_sol_source)?; if unlocked_sol_balance < total_unlocked_sol { return Err(Error::InsufficientFunds( vec![FundingSource::SystemAccount].into(), @@ -643,7 +652,7 @@ async fn check_payer_balances( } } } else if args.fee_payer.pubkey() == distribution_source { - let balance = client.get_balance(args.fee_payer.pubkey()).await?; + let balance = client.get_balance(&args.fee_payer.pubkey())?; if balance < fees + undistributed_tokens { return Err(Error::InsufficientFunds( vec![FundingSource::SystemAccount, FundingSource::FeePayer].into(), @@ -651,14 +660,14 @@ async fn check_payer_balances( )); } } else { - let fee_payer_balance = client.get_balance(args.fee_payer.pubkey()).await?; + let fee_payer_balance = client.get_balance(&args.fee_payer.pubkey())?; if fee_payer_balance < fees { return Err(Error::InsufficientFunds( vec![FundingSource::FeePayer].into(), lamports_to_sol(fees), )); } - let sender_balance = client.get_balance(distribution_source).await?; + let sender_balance = client.get_balance(&distribution_source)?; if sender_balance < undistributed_tokens { return Err(Error::InsufficientFunds( vec![FundingSource::SystemAccount].into(), @@ -669,7 +678,7 @@ async fn check_payer_balances( Ok(()) } -pub async fn process_balances(client: &mut BanksClient, args: &BalancesArgs) -> Result<(), Error> { +pub fn process_balances(client: &RpcClient, args: &BalancesArgs) -> Result<(), Error> { let allocations: Vec = read_allocations(&args.input_csv, None, false, args.spl_token_args.is_some())?; let allocations = merge_allocations(&allocations); @@ -692,11 +701,11 @@ pub async fn process_balances(client: &mut BanksClient, args: &BalancesArgs) -> for allocation in &allocations { if let Some(spl_token_args) = &args.spl_token_args { - print_token_balances(client, allocation, spl_token_args).await?; + print_token_balances(client, allocation, spl_token_args)?; } else { let address: Pubkey = allocation.recipient.parse().unwrap(); let expected = lamports_to_sol(allocation.amount); - let actual = lamports_to_sol(client.get_balance(address).await.unwrap()); + let actual = lamports_to_sol(client.get_balance(&address).unwrap()); println!( "{:<44} {:>24.9} {:>24.9} {:>24.9}", allocation.recipient, @@ -719,8 +728,8 @@ pub fn process_transaction_log(args: &TransactionLogArgs) -> Result<(), Error> { use crate::db::check_output_file; use solana_sdk::{pubkey::Pubkey, signature::Keypair}; use tempfile::{tempdir, NamedTempFile}; -pub async fn test_process_distribute_tokens_with_client( - client: &mut BanksClient, +pub fn test_process_distribute_tokens_with_client( + client: &RpcClient, sender_keypair: Keypair, transfer_amount: Option, ) { @@ -731,17 +740,12 @@ pub async fn test_process_distribute_tokens_with_client( &sender_keypair, &fee_payer.pubkey(), ) - .await .unwrap(); client - .process_transaction_with_commitment(transaction, CommitmentLevel::Recent) - .await + .send_and_confirm_transaction_with_spinner(&transaction) .unwrap(); assert_eq!( - client - .get_balance_with_commitment(fee_payer.pubkey(), CommitmentLevel::Recent) - .await - .unwrap(), + client.get_balance(&fee_payer.pubkey()).unwrap(), sol_to_lamports(1.0), ); @@ -784,7 +788,7 @@ pub async fn test_process_distribute_tokens_with_client( spl_token_args: None, transfer_amount, }; - let confirmations = process_allocations(client, &args).await.unwrap(); + let confirmations = process_allocations(client, &args).unwrap(); assert_eq!(confirmations, None); let transaction_infos = @@ -793,33 +797,24 @@ pub async fn test_process_distribute_tokens_with_client( assert_eq!(transaction_infos[0].recipient, alice_pubkey); assert_eq!(transaction_infos[0].amount, expected_amount); - assert_eq!( - client.get_balance(alice_pubkey).await.unwrap(), - expected_amount, - ); + assert_eq!(client.get_balance(&alice_pubkey).unwrap(), expected_amount); check_output_file(&output_path, &db::open_db(&transaction_db, true).unwrap()); // Now, run it again, and check there's no double-spend. - process_allocations(client, &args).await.unwrap(); + process_allocations(client, &args).unwrap(); let transaction_infos = db::read_transaction_infos(&db::open_db(&transaction_db, true).unwrap()); assert_eq!(transaction_infos.len(), 1); assert_eq!(transaction_infos[0].recipient, alice_pubkey); assert_eq!(transaction_infos[0].amount, expected_amount); - assert_eq!( - client.get_balance(alice_pubkey).await.unwrap(), - expected_amount, - ); + assert_eq!(client.get_balance(&alice_pubkey).unwrap(), expected_amount); check_output_file(&output_path, &db::open_db(&transaction_db, true).unwrap()); } -pub async fn test_process_distribute_stake_with_client( - client: &mut BanksClient, - sender_keypair: Keypair, -) { +pub fn test_process_distribute_stake_with_client(client: &RpcClient, sender_keypair: Keypair) { let fee_payer = Keypair::new(); let transaction = transfer( client, @@ -827,11 +822,9 @@ pub async fn test_process_distribute_stake_with_client( &sender_keypair, &fee_payer.pubkey(), ) - .await .unwrap(); client - .process_transaction_with_commitment(transaction, CommitmentLevel::Recent) - .await + .send_and_confirm_transaction_with_spinner(&transaction) .unwrap(); let stake_account_keypair = Keypair::new(); @@ -853,11 +846,10 @@ pub async fn test_process_distribute_stake_with_client( ); let message = Message::new(&instructions, Some(&sender_keypair.pubkey())); let signers = [&sender_keypair, &stake_account_keypair]; - let blockhash = client.get_recent_blockhash().await.unwrap(); + let (blockhash, _fees) = client.get_recent_blockhash().unwrap(); let transaction = Transaction::new(&signers, message, blockhash); client - .process_transaction_with_commitment(transaction, CommitmentLevel::Recent) - .await + .send_and_confirm_transaction_with_spinner(&transaction) .unwrap(); let expected_amount = sol_to_lamports(1000.0); @@ -904,7 +896,7 @@ pub async fn test_process_distribute_stake_with_client( sender_keypair: Box::new(sender_keypair), transfer_amount: None, }; - let confirmations = process_allocations(client, &args).await.unwrap(); + let confirmations = process_allocations(client, &args).unwrap(); assert_eq!(confirmations, None); let transaction_infos = @@ -914,19 +906,19 @@ pub async fn test_process_distribute_stake_with_client( assert_eq!(transaction_infos[0].amount, expected_amount); assert_eq!( - client.get_balance(alice_pubkey).await.unwrap(), + client.get_balance(&alice_pubkey).unwrap(), sol_to_lamports(1.0), ); let new_stake_account_address = transaction_infos[0].new_stake_account_address.unwrap(); assert_eq!( - client.get_balance(new_stake_account_address).await.unwrap(), + client.get_balance(&new_stake_account_address).unwrap(), expected_amount - sol_to_lamports(1.0), ); check_output_file(&output_path, &db::open_db(&transaction_db, true).unwrap()); // Now, run it again, and check there's no double-spend. - process_allocations(client, &args).await.unwrap(); + process_allocations(client, &args).unwrap(); let transaction_infos = db::read_transaction_infos(&db::open_db(&transaction_db, true).unwrap()); assert_eq!(transaction_infos.len(), 1); @@ -934,11 +926,11 @@ pub async fn test_process_distribute_stake_with_client( assert_eq!(transaction_infos[0].amount, expected_amount); assert_eq!( - client.get_balance(alice_pubkey).await.unwrap(), + client.get_balance(&alice_pubkey).unwrap(), sol_to_lamports(1.0), ); assert_eq!( - client.get_balance(new_stake_account_address).await.unwrap(), + client.get_balance(&new_stake_account_address).unwrap(), expected_amount - sol_to_lamports(1.0), ); @@ -946,57 +938,82 @@ pub async fn test_process_distribute_stake_with_client( } #[cfg(test)] -pub(crate) mod tests { +mod tests { use super::*; - use solana_banks_client::start_client; - use solana_banks_server::banks_server::start_local_server; - use solana_runtime::{bank::Bank, bank_forks::BankForks}; + use solana_client::rpc_client::get_rpc_request_str; + use solana_core::test_validator::TestValidator; use solana_sdk::{ - fee_calculator::FeeRateGovernor, - genesis_config::create_genesis_config, + clock::DEFAULT_MS_PER_SLOT, signature::{read_keypair_file, write_keypair_file}, }; use solana_stake_program::stake_instruction::StakeInstruction; - use std::sync::{Arc, RwLock}; - use tokio::runtime::Runtime; + use std::fs::remove_dir_all; + + // This is a quick hack until TestValidator can be initialized with fees from block 0 + fn test_validator_block_0_fee_workaround(client: &RpcClient) { + while client + .get_recent_blockhash() + .unwrap() + .1 + .lamports_per_signature + == 0 + { + sleep(Duration::from_millis(DEFAULT_MS_PER_SLOT)); + } + } #[test] fn test_process_token_allocations() { - let (genesis_config, sender_keypair) = create_genesis_config(sol_to_lamports(9_000_000.0)); - let bank_forks = Arc::new(RwLock::new(BankForks::new(Bank::new(&genesis_config)))); - Runtime::new().unwrap().block_on(async { - let transport = start_local_server(&bank_forks).await; - let mut banks_client = start_client(transport).await.unwrap(); - test_process_distribute_tokens_with_client(&mut banks_client, sender_keypair, None) - .await; - }); + let TestValidator { + server, + leader_data, + alice, + ledger_path, + .. + } = TestValidator::run(); + let url = get_rpc_request_str(leader_data.rpc, false); + let client = RpcClient::new_with_commitment(url, CommitmentConfig::recent()); + test_process_distribute_tokens_with_client(&client, alice, None); + + // Explicit cleanup, otherwise "pure virtual method called" crash in Docker + server.close().unwrap(); + remove_dir_all(ledger_path).unwrap(); } #[test] fn test_process_transfer_amount_allocations() { - let (genesis_config, sender_keypair) = create_genesis_config(sol_to_lamports(9_000_000.0)); - let bank_forks = Arc::new(RwLock::new(BankForks::new(Bank::new(&genesis_config)))); - Runtime::new().unwrap().block_on(async { - let transport = start_local_server(&bank_forks).await; - let mut banks_client = start_client(transport).await.unwrap(); - test_process_distribute_tokens_with_client( - &mut banks_client, - sender_keypair, - Some(sol_to_lamports(1.5)), - ) - .await; - }); + let TestValidator { + server, + leader_data, + alice, + ledger_path, + .. + } = TestValidator::run(); + let url = get_rpc_request_str(leader_data.rpc, false); + let client = RpcClient::new_with_commitment(url, CommitmentConfig::recent()); + test_process_distribute_tokens_with_client(&client, alice, Some(sol_to_lamports(1.5))); + + // Explicit cleanup, otherwise "pure virtual method called" crash in Docker + server.close().unwrap(); + remove_dir_all(ledger_path).unwrap(); } #[test] fn test_process_stake_allocations() { - let (genesis_config, sender_keypair) = create_genesis_config(sol_to_lamports(9_000_000.0)); - let bank_forks = Arc::new(RwLock::new(BankForks::new(Bank::new(&genesis_config)))); - Runtime::new().unwrap().block_on(async { - let transport = start_local_server(&bank_forks).await; - let mut banks_client = start_client(transport).await.unwrap(); - test_process_distribute_stake_with_client(&mut banks_client, sender_keypair).await; - }); + let TestValidator { + server, + leader_data, + alice, + ledger_path, + .. + } = TestValidator::run(); + let url = get_rpc_request_str(leader_data.rpc, false); + let client = RpcClient::new_with_commitment(url, CommitmentConfig::recent()); + test_process_distribute_stake_with_client(&client, alice); + + // Explicit cleanup, otherwise "pure virtual method called" crash in Docker + server.close().unwrap(); + remove_dir_all(ledger_path).unwrap(); } #[test] @@ -1268,7 +1285,7 @@ pub(crate) mod tests { } } - pub fn tmp_file_path(name: &str, pubkey: &Pubkey) -> String { + fn tmp_file_path(name: &str, pubkey: &Pubkey) -> String { use std::env; let out_dir = env::var("FARF_DIR").unwrap_or_else(|_| "farf".to_string()); @@ -1305,185 +1322,180 @@ pub(crate) mod tests { fn test_check_payer_balances_distribute_tokens_single_payer() { let fees = 10_000; let fees_in_sol = lamports_to_sol(fees); - let (mut genesis_config, sender_keypair) = - create_genesis_config(sol_to_lamports(9_000_000.0)); - genesis_config.fee_rate_governor = FeeRateGovernor::new(fees, 0); - let bank_forks = Arc::new(RwLock::new(BankForks::new(Bank::new(&genesis_config)))); - Runtime::new().unwrap().block_on(async { - let transport = start_local_server(&bank_forks).await; - let mut banks_client = start_client(transport).await.unwrap(); + let TestValidator { + server, + leader_data, + alice, + ledger_path, + .. + } = TestValidator::run_with_fees(fees); + let url = get_rpc_request_str(leader_data.rpc, false); + let client = RpcClient::new_with_commitment(url, CommitmentConfig::recent()); + let sender_keypair_file = tmp_file_path("keypair_file", &alice.pubkey()); + write_keypair_file(&alice, &sender_keypair_file).unwrap(); - let sender_keypair_file = tmp_file_path("keypair_file", &sender_keypair.pubkey()); - write_keypair_file(&sender_keypair, &sender_keypair_file).unwrap(); + test_validator_block_0_fee_workaround(&client); - let allocation_amount = 1000.0; + let allocation_amount = 1000.0; - // Fully funded payer - let (allocations, mut args) = initialize_check_payer_balances_inputs( - sol_to_lamports(allocation_amount), - &sender_keypair_file, - &sender_keypair_file, - None, + // Fully funded payer + let (allocations, mut args) = initialize_check_payer_balances_inputs( + sol_to_lamports(allocation_amount), + &sender_keypair_file, + &sender_keypair_file, + None, + ); + check_payer_balances(1, &allocations, &client, &args).unwrap(); + + // Unfunded payer + let unfunded_payer = Keypair::new(); + let unfunded_payer_keypair_file = tmp_file_path("keypair_file", &unfunded_payer.pubkey()); + write_keypair_file(&unfunded_payer, &unfunded_payer_keypair_file).unwrap(); + args.sender_keypair = read_keypair_file(&unfunded_payer_keypair_file) + .unwrap() + .into(); + args.fee_payer = read_keypair_file(&unfunded_payer_keypair_file) + .unwrap() + .into(); + + let err_result = check_payer_balances(1, &allocations, &client, &args).unwrap_err(); + if let Error::InsufficientFunds(sources, amount) = err_result { + assert_eq!( + sources, + vec![FundingSource::SystemAccount, FundingSource::FeePayer].into() ); - check_payer_balances(1, &allocations, &mut banks_client, &args) - .await - .unwrap(); + assert!((amount - (allocation_amount + fees_in_sol)).abs() < f64::EPSILON); + } else { + panic!("check_payer_balances should have errored"); + } - // Unfunded payer - let unfunded_payer = Keypair::new(); - let unfunded_payer_keypair_file = - tmp_file_path("keypair_file", &unfunded_payer.pubkey()); - write_keypair_file(&unfunded_payer, &unfunded_payer_keypair_file).unwrap(); - args.sender_keypair = read_keypair_file(&unfunded_payer_keypair_file) - .unwrap() - .into(); - args.fee_payer = read_keypair_file(&unfunded_payer_keypair_file) - .unwrap() - .into(); - - let err_result = check_payer_balances(1, &allocations, &mut banks_client, &args) - .await - .unwrap_err(); - if let Error::InsufficientFunds(sources, amount) = err_result { - assert_eq!( - sources, - vec![FundingSource::SystemAccount, FundingSource::FeePayer].into() - ); - assert!((amount - (allocation_amount + fees_in_sol)).abs() < f64::EPSILON); - } else { - panic!("check_payer_balances should have errored"); - } - - // Payer funded enough for distribution only - let partially_funded_payer = Keypair::new(); - let partially_funded_payer_keypair_file = - tmp_file_path("keypair_file", &partially_funded_payer.pubkey()); - write_keypair_file( - &partially_funded_payer, - &partially_funded_payer_keypair_file, - ) + // Payer funded enough for distribution only + let partially_funded_payer = Keypair::new(); + let partially_funded_payer_keypair_file = + tmp_file_path("keypair_file", &partially_funded_payer.pubkey()); + write_keypair_file( + &partially_funded_payer, + &partially_funded_payer_keypair_file, + ) + .unwrap(); + let transaction = transfer( + &client, + sol_to_lamports(allocation_amount), + &alice, + &partially_funded_payer.pubkey(), + ) + .unwrap(); + client + .send_and_confirm_transaction_with_spinner(&transaction) .unwrap(); - let transaction = transfer( - &mut banks_client, - sol_to_lamports(allocation_amount), - &sender_keypair, - &partially_funded_payer.pubkey(), - ) - .await - .unwrap(); - banks_client - .process_transaction_with_commitment(transaction, CommitmentLevel::Recent) - .await - .unwrap(); - args.sender_keypair = read_keypair_file(&partially_funded_payer_keypair_file) - .unwrap() - .into(); - args.fee_payer = read_keypair_file(&partially_funded_payer_keypair_file) - .unwrap() - .into(); - let err_result = check_payer_balances(1, &allocations, &mut banks_client, &args) - .await - .unwrap_err(); - if let Error::InsufficientFunds(sources, amount) = err_result { - assert_eq!( - sources, - vec![FundingSource::SystemAccount, FundingSource::FeePayer].into() - ); - assert!((amount - (allocation_amount + fees_in_sol)).abs() < f64::EPSILON); - } else { - panic!("check_payer_balances should have errored"); - } - }); + args.sender_keypair = read_keypair_file(&partially_funded_payer_keypair_file) + .unwrap() + .into(); + args.fee_payer = read_keypair_file(&partially_funded_payer_keypair_file) + .unwrap() + .into(); + let err_result = check_payer_balances(1, &allocations, &client, &args).unwrap_err(); + if let Error::InsufficientFunds(sources, amount) = err_result { + assert_eq!( + sources, + vec![FundingSource::SystemAccount, FundingSource::FeePayer].into() + ); + assert!((amount - (allocation_amount + fees_in_sol)).abs() < f64::EPSILON); + } else { + panic!("check_payer_balances should have errored"); + } + + // Explicit cleanup, otherwise "pure virtual method called" crash in Docker + server.close().unwrap(); + remove_dir_all(ledger_path).unwrap(); } #[test] fn test_check_payer_balances_distribute_tokens_separate_payers() { let fees = 10_000; let fees_in_sol = lamports_to_sol(fees); - let (mut genesis_config, sender_keypair) = - create_genesis_config(sol_to_lamports(9_000_000.0)); - genesis_config.fee_rate_governor = FeeRateGovernor::new(fees, 0); - let bank_forks = Arc::new(RwLock::new(BankForks::new(Bank::new(&genesis_config)))); - Runtime::new().unwrap().block_on(async { - let transport = start_local_server(&bank_forks).await; - let mut banks_client = start_client(transport).await.unwrap(); + let TestValidator { + server, + leader_data, + alice, + ledger_path, + .. + } = TestValidator::run_with_fees(fees); + let url = get_rpc_request_str(leader_data.rpc, false); + let client = RpcClient::new_with_commitment(url, CommitmentConfig::recent()); - let sender_keypair_file = tmp_file_path("keypair_file", &sender_keypair.pubkey()); - write_keypair_file(&sender_keypair, &sender_keypair_file).unwrap(); + test_validator_block_0_fee_workaround(&client); - let allocation_amount = 1000.0; + let sender_keypair_file = tmp_file_path("keypair_file", &alice.pubkey()); + write_keypair_file(&alice, &sender_keypair_file).unwrap(); - let funded_payer = Keypair::new(); - let funded_payer_keypair_file = tmp_file_path("keypair_file", &funded_payer.pubkey()); - write_keypair_file(&funded_payer, &funded_payer_keypair_file).unwrap(); - let transaction = transfer( - &mut banks_client, - sol_to_lamports(allocation_amount), - &sender_keypair, - &funded_payer.pubkey(), - ) - .await + let allocation_amount = 1000.0; + + let funded_payer = Keypair::new(); + let funded_payer_keypair_file = tmp_file_path("keypair_file", &funded_payer.pubkey()); + write_keypair_file(&funded_payer, &funded_payer_keypair_file).unwrap(); + let transaction = transfer( + &client, + sol_to_lamports(allocation_amount), + &alice, + &funded_payer.pubkey(), + ) + .unwrap(); + client + .send_and_confirm_transaction_with_spinner(&transaction) .unwrap(); - banks_client - .process_transaction_with_commitment(transaction, CommitmentLevel::Recent) - .await - .unwrap(); - // Fully funded payers - let (allocations, mut args) = initialize_check_payer_balances_inputs( - sol_to_lamports(allocation_amount), - &funded_payer_keypair_file, - &sender_keypair_file, - None, - ); - check_payer_balances(1, &allocations, &mut banks_client, &args) - .await - .unwrap(); + // Fully funded payers + let (allocations, mut args) = initialize_check_payer_balances_inputs( + sol_to_lamports(allocation_amount), + &funded_payer_keypair_file, + &sender_keypair_file, + None, + ); + check_payer_balances(1, &allocations, &client, &args).unwrap(); - // Unfunded sender - let unfunded_payer = Keypair::new(); - let unfunded_payer_keypair_file = - tmp_file_path("keypair_file", &unfunded_payer.pubkey()); - write_keypair_file(&unfunded_payer, &unfunded_payer_keypair_file).unwrap(); - args.sender_keypair = read_keypair_file(&unfunded_payer_keypair_file) - .unwrap() - .into(); - args.fee_payer = read_keypair_file(&sender_keypair_file).unwrap().into(); + // Unfunded sender + let unfunded_payer = Keypair::new(); + let unfunded_payer_keypair_file = tmp_file_path("keypair_file", &unfunded_payer.pubkey()); + write_keypair_file(&unfunded_payer, &unfunded_payer_keypair_file).unwrap(); + args.sender_keypair = read_keypair_file(&unfunded_payer_keypair_file) + .unwrap() + .into(); + args.fee_payer = read_keypair_file(&sender_keypair_file).unwrap().into(); - let err_result = check_payer_balances(1, &allocations, &mut banks_client, &args) - .await - .unwrap_err(); - if let Error::InsufficientFunds(sources, amount) = err_result { - assert_eq!(sources, vec![FundingSource::SystemAccount].into()); - assert!((amount - allocation_amount).abs() < f64::EPSILON); - } else { - panic!("check_payer_balances should have errored"); - } + let err_result = check_payer_balances(1, &allocations, &client, &args).unwrap_err(); + if let Error::InsufficientFunds(sources, amount) = err_result { + assert_eq!(sources, vec![FundingSource::SystemAccount].into()); + assert!((amount - allocation_amount).abs() < f64::EPSILON); + } else { + panic!("check_payer_balances should have errored"); + } - // Unfunded fee payer - args.sender_keypair = read_keypair_file(&sender_keypair_file).unwrap().into(); - args.fee_payer = read_keypair_file(&unfunded_payer_keypair_file) - .unwrap() - .into(); + // Unfunded fee payer + args.sender_keypair = read_keypair_file(&sender_keypair_file).unwrap().into(); + args.fee_payer = read_keypair_file(&unfunded_payer_keypair_file) + .unwrap() + .into(); - let err_result = check_payer_balances(1, &allocations, &mut banks_client, &args) - .await - .unwrap_err(); - if let Error::InsufficientFunds(sources, amount) = err_result { - assert_eq!(sources, vec![FundingSource::FeePayer].into()); - assert!((amount - fees_in_sol).abs() < f64::EPSILON); - } else { - panic!("check_payer_balances should have errored"); - } - }); + let err_result = check_payer_balances(1, &allocations, &client, &args).unwrap_err(); + if let Error::InsufficientFunds(sources, amount) = err_result { + assert_eq!(sources, vec![FundingSource::FeePayer].into()); + assert!((amount - fees_in_sol).abs() < f64::EPSILON); + } else { + panic!("check_payer_balances should have errored"); + } + + // Explicit cleanup, otherwise "pure virtual method called" crash in Docker + server.close().unwrap(); + remove_dir_all(ledger_path).unwrap(); } - async fn initialize_stake_account( + fn initialize_stake_account( stake_account_amount: u64, unlocked_sol: u64, sender_keypair: &Keypair, - banks_client: &mut BanksClient, + client: &RpcClient, ) -> StakeArgs { let stake_account_keypair = Keypair::new(); let stake_account_address = stake_account_keypair.pubkey(); @@ -1504,11 +1516,10 @@ pub(crate) mod tests { ); let message = Message::new(&instructions, Some(&sender_keypair.pubkey())); let signers = [sender_keypair, &stake_account_keypair]; - let blockhash = banks_client.get_recent_blockhash().await.unwrap(); + let (blockhash, _fees) = client.get_recent_blockhash().unwrap(); let transaction = Transaction::new(&signers, message, blockhash); - banks_client - .process_transaction_with_commitment(transaction, CommitmentLevel::Recent) - .await + client + .send_and_confirm_transaction_with_spinner(&transaction) .unwrap(); StakeArgs { @@ -1524,213 +1535,203 @@ pub(crate) mod tests { fn test_check_payer_balances_distribute_stakes_single_payer() { let fees = 10_000; let fees_in_sol = lamports_to_sol(fees); - let (mut genesis_config, sender_keypair) = - create_genesis_config(sol_to_lamports(9_000_000.0)); - genesis_config.fee_rate_governor = FeeRateGovernor::new(fees, 0); - let bank_forks = Arc::new(RwLock::new(BankForks::new(Bank::new(&genesis_config)))); - Runtime::new().unwrap().block_on(async { - let transport = start_local_server(&bank_forks).await; - let mut banks_client = start_client(transport).await.unwrap(); + let TestValidator { + server, + leader_data, + alice, + ledger_path, + .. + } = TestValidator::run_with_fees(fees); + let url = get_rpc_request_str(leader_data.rpc, false); + let client = RpcClient::new_with_commitment(url, CommitmentConfig::recent()); - let sender_keypair_file = tmp_file_path("keypair_file", &sender_keypair.pubkey()); - write_keypair_file(&sender_keypair, &sender_keypair_file).unwrap(); + test_validator_block_0_fee_workaround(&client); - let allocation_amount = 1000.0; - let unlocked_sol = 1.0; - let stake_args = initialize_stake_account( - sol_to_lamports(allocation_amount), - sol_to_lamports(unlocked_sol), - &sender_keypair, - &mut banks_client, - ) - .await; + let sender_keypair_file = tmp_file_path("keypair_file", &alice.pubkey()); + write_keypair_file(&alice, &sender_keypair_file).unwrap(); - // Fully funded payer & stake account - let (allocations, mut args) = initialize_check_payer_balances_inputs( - sol_to_lamports(allocation_amount), - &sender_keypair_file, - &sender_keypair_file, - Some(stake_args), + let allocation_amount = 1000.0; + let unlocked_sol = 1.0; + let stake_args = initialize_stake_account( + sol_to_lamports(allocation_amount), + sol_to_lamports(unlocked_sol), + &alice, + &client, + ); + + // Fully funded payer & stake account + let (allocations, mut args) = initialize_check_payer_balances_inputs( + sol_to_lamports(allocation_amount), + &sender_keypair_file, + &sender_keypair_file, + Some(stake_args), + ); + check_payer_balances(1, &allocations, &client, &args).unwrap(); + + // Underfunded stake-account + let expensive_allocation_amount = 5000.0; + let expensive_allocations = vec![Allocation { + recipient: solana_sdk::pubkey::new_rand().to_string(), + amount: sol_to_lamports(expensive_allocation_amount), + lockup_date: "".to_string(), + }]; + let err_result = + check_payer_balances(1, &expensive_allocations, &client, &args).unwrap_err(); + if let Error::InsufficientFunds(sources, amount) = err_result { + assert_eq!(sources, vec![FundingSource::StakeAccount].into()); + assert!((amount - (expensive_allocation_amount - unlocked_sol)).abs() < f64::EPSILON); + } else { + panic!("check_payer_balances should have errored"); + } + + // Unfunded payer + let unfunded_payer = Keypair::new(); + let unfunded_payer_keypair_file = tmp_file_path("keypair_file", &unfunded_payer.pubkey()); + write_keypair_file(&unfunded_payer, &unfunded_payer_keypair_file).unwrap(); + args.sender_keypair = read_keypair_file(&unfunded_payer_keypair_file) + .unwrap() + .into(); + args.fee_payer = read_keypair_file(&unfunded_payer_keypair_file) + .unwrap() + .into(); + + let err_result = check_payer_balances(1, &allocations, &client, &args).unwrap_err(); + if let Error::InsufficientFunds(sources, amount) = err_result { + assert_eq!( + sources, + vec![FundingSource::SystemAccount, FundingSource::FeePayer].into() ); - check_payer_balances(1, &allocations, &mut banks_client, &args) - .await - .unwrap(); + assert!((amount - (unlocked_sol + fees_in_sol)).abs() < f64::EPSILON); + } else { + panic!("check_payer_balances should have errored"); + } - // Underfunded stake-account - let expensive_allocation_amount = 5000.0; - let expensive_allocations = vec![Allocation { - recipient: solana_sdk::pubkey::new_rand().to_string(), - amount: sol_to_lamports(expensive_allocation_amount), - lockup_date: "".to_string(), - }]; - let err_result = - check_payer_balances(1, &expensive_allocations, &mut banks_client, &args) - .await - .unwrap_err(); - if let Error::InsufficientFunds(sources, amount) = err_result { - assert_eq!(sources, vec![FundingSource::StakeAccount].into()); - assert!( - (amount - (expensive_allocation_amount - unlocked_sol)).abs() < f64::EPSILON - ); - } else { - panic!("check_payer_balances should have errored"); - } - - // Unfunded payer - let unfunded_payer = Keypair::new(); - let unfunded_payer_keypair_file = - tmp_file_path("keypair_file", &unfunded_payer.pubkey()); - write_keypair_file(&unfunded_payer, &unfunded_payer_keypair_file).unwrap(); - args.sender_keypair = read_keypair_file(&unfunded_payer_keypair_file) - .unwrap() - .into(); - args.fee_payer = read_keypair_file(&unfunded_payer_keypair_file) - .unwrap() - .into(); - - let err_result = check_payer_balances(1, &allocations, &mut banks_client, &args) - .await - .unwrap_err(); - if let Error::InsufficientFunds(sources, amount) = err_result { - assert_eq!( - sources, - vec![FundingSource::SystemAccount, FundingSource::FeePayer].into() - ); - assert!((amount - (unlocked_sol + fees_in_sol)).abs() < f64::EPSILON); - } else { - panic!("check_payer_balances should have errored"); - } - - // Payer funded enough for distribution only - let partially_funded_payer = Keypair::new(); - let partially_funded_payer_keypair_file = - tmp_file_path("keypair_file", &partially_funded_payer.pubkey()); - write_keypair_file( - &partially_funded_payer, - &partially_funded_payer_keypair_file, - ) + // Payer funded enough for distribution only + let partially_funded_payer = Keypair::new(); + let partially_funded_payer_keypair_file = + tmp_file_path("keypair_file", &partially_funded_payer.pubkey()); + write_keypair_file( + &partially_funded_payer, + &partially_funded_payer_keypair_file, + ) + .unwrap(); + let transaction = transfer( + &client, + sol_to_lamports(unlocked_sol), + &alice, + &partially_funded_payer.pubkey(), + ) + .unwrap(); + client + .send_and_confirm_transaction_with_spinner(&transaction) .unwrap(); - let transaction = transfer( - &mut banks_client, - sol_to_lamports(unlocked_sol), - &sender_keypair, - &partially_funded_payer.pubkey(), - ) - .await - .unwrap(); - banks_client - .process_transaction_with_commitment(transaction, CommitmentLevel::Recent) - .await - .unwrap(); - args.sender_keypair = read_keypair_file(&partially_funded_payer_keypair_file) - .unwrap() - .into(); - args.fee_payer = read_keypair_file(&partially_funded_payer_keypair_file) - .unwrap() - .into(); - let err_result = check_payer_balances(1, &allocations, &mut banks_client, &args) - .await - .unwrap_err(); - if let Error::InsufficientFunds(sources, amount) = err_result { - assert_eq!( - sources, - vec![FundingSource::SystemAccount, FundingSource::FeePayer].into() - ); - assert!((amount - (unlocked_sol + fees_in_sol)).abs() < f64::EPSILON); - } else { - panic!("check_payer_balances should have errored"); - } - }); + args.sender_keypair = read_keypair_file(&partially_funded_payer_keypair_file) + .unwrap() + .into(); + args.fee_payer = read_keypair_file(&partially_funded_payer_keypair_file) + .unwrap() + .into(); + let err_result = check_payer_balances(1, &allocations, &client, &args).unwrap_err(); + if let Error::InsufficientFunds(sources, amount) = err_result { + assert_eq!( + sources, + vec![FundingSource::SystemAccount, FundingSource::FeePayer].into() + ); + assert!((amount - (unlocked_sol + fees_in_sol)).abs() < f64::EPSILON); + } else { + panic!("check_payer_balances should have errored"); + } + + // Explicit cleanup, otherwise "pure virtual method called" crash in Docker + server.close().unwrap(); + remove_dir_all(ledger_path).unwrap(); } #[test] fn test_check_payer_balances_distribute_stakes_separate_payers() { let fees = 10_000; let fees_in_sol = lamports_to_sol(fees); - let (mut genesis_config, sender_keypair) = - create_genesis_config(sol_to_lamports(9_000_000.0)); - genesis_config.fee_rate_governor = FeeRateGovernor::new(fees, 0); - let bank_forks = Arc::new(RwLock::new(BankForks::new(Bank::new(&genesis_config)))); - Runtime::new().unwrap().block_on(async { - let transport = start_local_server(&bank_forks).await; - let mut banks_client = start_client(transport).await.unwrap(); + let TestValidator { + server, + leader_data, + alice, + ledger_path, + .. + } = TestValidator::run_with_fees(fees); + let url = get_rpc_request_str(leader_data.rpc, false); + let client = RpcClient::new_with_commitment(url, CommitmentConfig::recent()); - let sender_keypair_file = tmp_file_path("keypair_file", &sender_keypair.pubkey()); - write_keypair_file(&sender_keypair, &sender_keypair_file).unwrap(); + let sender_keypair_file = tmp_file_path("keypair_file", &alice.pubkey()); + write_keypair_file(&alice, &sender_keypair_file).unwrap(); - let allocation_amount = 1000.0; - let unlocked_sol = 1.0; - let stake_args = initialize_stake_account( - sol_to_lamports(allocation_amount), - sol_to_lamports(unlocked_sol), - &sender_keypair, - &mut banks_client, - ) - .await; + test_validator_block_0_fee_workaround(&client); - let funded_payer = Keypair::new(); - let funded_payer_keypair_file = tmp_file_path("keypair_file", &funded_payer.pubkey()); - write_keypair_file(&funded_payer, &funded_payer_keypair_file).unwrap(); - let transaction = transfer( - &mut banks_client, - sol_to_lamports(unlocked_sol), - &sender_keypair, - &funded_payer.pubkey(), - ) - .await + let allocation_amount = 1000.0; + let unlocked_sol = 1.0; + let stake_args = initialize_stake_account( + sol_to_lamports(allocation_amount), + sol_to_lamports(unlocked_sol), + &alice, + &client, + ); + + let funded_payer = Keypair::new(); + let funded_payer_keypair_file = tmp_file_path("keypair_file", &funded_payer.pubkey()); + write_keypair_file(&funded_payer, &funded_payer_keypair_file).unwrap(); + let transaction = transfer( + &client, + sol_to_lamports(unlocked_sol), + &alice, + &funded_payer.pubkey(), + ) + .unwrap(); + client + .send_and_confirm_transaction_with_spinner(&transaction) .unwrap(); - banks_client - .process_transaction_with_commitment(transaction, CommitmentLevel::Recent) - .await - .unwrap(); - // Fully funded payers - let (allocations, mut args) = initialize_check_payer_balances_inputs( - sol_to_lamports(allocation_amount), - &funded_payer_keypair_file, - &sender_keypair_file, - Some(stake_args), - ); - check_payer_balances(1, &allocations, &mut banks_client, &args) - .await - .unwrap(); + // Fully funded payers + let (allocations, mut args) = initialize_check_payer_balances_inputs( + sol_to_lamports(allocation_amount), + &funded_payer_keypair_file, + &sender_keypair_file, + Some(stake_args), + ); + check_payer_balances(1, &allocations, &client, &args).unwrap(); - // Unfunded sender - let unfunded_payer = Keypair::new(); - let unfunded_payer_keypair_file = - tmp_file_path("keypair_file", &unfunded_payer.pubkey()); - write_keypair_file(&unfunded_payer, &unfunded_payer_keypair_file).unwrap(); - args.sender_keypair = read_keypair_file(&unfunded_payer_keypair_file) - .unwrap() - .into(); - args.fee_payer = read_keypair_file(&sender_keypair_file).unwrap().into(); + // Unfunded sender + let unfunded_payer = Keypair::new(); + let unfunded_payer_keypair_file = tmp_file_path("keypair_file", &unfunded_payer.pubkey()); + write_keypair_file(&unfunded_payer, &unfunded_payer_keypair_file).unwrap(); + args.sender_keypair = read_keypair_file(&unfunded_payer_keypair_file) + .unwrap() + .into(); + args.fee_payer = read_keypair_file(&sender_keypair_file).unwrap().into(); - let err_result = check_payer_balances(1, &allocations, &mut banks_client, &args) - .await - .unwrap_err(); - if let Error::InsufficientFunds(sources, amount) = err_result { - assert_eq!(sources, vec![FundingSource::SystemAccount].into()); - assert!((amount - unlocked_sol).abs() < f64::EPSILON); - } else { - panic!("check_payer_balances should have errored"); - } + let err_result = check_payer_balances(1, &allocations, &client, &args).unwrap_err(); + if let Error::InsufficientFunds(sources, amount) = err_result { + assert_eq!(sources, vec![FundingSource::SystemAccount].into()); + assert!((amount - unlocked_sol).abs() < f64::EPSILON); + } else { + panic!("check_payer_balances should have errored"); + } - // Unfunded fee payer - args.sender_keypair = read_keypair_file(&sender_keypair_file).unwrap().into(); - args.fee_payer = read_keypair_file(&unfunded_payer_keypair_file) - .unwrap() - .into(); + // Unfunded fee payer + args.sender_keypair = read_keypair_file(&sender_keypair_file).unwrap().into(); + args.fee_payer = read_keypair_file(&unfunded_payer_keypair_file) + .unwrap() + .into(); - let err_result = check_payer_balances(1, &allocations, &mut banks_client, &args) - .await - .unwrap_err(); - if let Error::InsufficientFunds(sources, amount) = err_result { - assert_eq!(sources, vec![FundingSource::FeePayer].into()); - assert!((amount - fees_in_sol).abs() < f64::EPSILON); - } else { - panic!("check_payer_balances should have errored"); - } - }); + let err_result = check_payer_balances(1, &allocations, &client, &args).unwrap_err(); + if let Error::InsufficientFunds(sources, amount) = err_result { + assert_eq!(sources, vec![FundingSource::FeePayer].into()); + assert!((amount - fees_in_sol).abs() < f64::EPSILON); + } else { + panic!("check_payer_balances should have errored"); + } + + // Explicit cleanup, otherwise "pure virtual method called" crash in Docker + server.close().unwrap(); + remove_dir_all(ledger_path).unwrap(); } } diff --git a/tokens/src/db.rs b/tokens/src/db.rs index b0743397ac..4e86521ccc 100644 --- a/tokens/src/db.rs +++ b/tokens/src/db.rs @@ -1,8 +1,8 @@ use chrono::prelude::*; use pickledb::{error::Error, PickleDb, PickleDbDumpPolicy}; use serde::{Deserialize, Serialize}; -use solana_banks_client::TransactionStatus; use solana_sdk::{clock::Slot, pubkey::Pubkey, signature::Signature, transaction::Transaction}; +use solana_transaction_status::TransactionStatus; use std::{cmp::Ordering, fs, io, path::Path}; #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] @@ -306,6 +306,7 @@ mod tests { slot: 0, confirmations: Some(1), err: None, + status: Ok(()), }; assert_eq!( update_finalized_transaction(&mut db, &signature, Some(transaction_status), 0, 0) @@ -332,6 +333,7 @@ mod tests { slot: 0, confirmations: None, err: Some(TransactionError::AccountNotFound), + status: Ok(()), }; assert_eq!( update_finalized_transaction(&mut db, &signature, Some(transaction_status), 0, 0) @@ -355,6 +357,7 @@ mod tests { slot: 0, confirmations: None, err: None, + status: Ok(()), }; assert_eq!( update_finalized_transaction(&mut db, &signature, Some(transaction_status), 0, 0) diff --git a/tokens/src/main.rs b/tokens/src/main.rs index a32e89ef24..85804c0dd8 100644 --- a/tokens/src/main.rs +++ b/tokens/src/main.rs @@ -1,9 +1,7 @@ -use solana_banks_client::start_tcp_client; use solana_cli_config::{Config, CONFIG_FILE}; +use solana_client::rpc_client::RpcClient; use solana_tokens::{arg_parser::parse_args, args::Command, commands, spl_token}; use std::{env, error::Error, path::Path, process}; -use tokio::runtime::Runtime; -use url::Url; fn main() -> Result<(), Box> { let command_args = parse_args(env::args_os())?; @@ -18,27 +16,16 @@ fn main() -> Result<(), Box> { Config::default() }; let json_rpc_url = command_args.url.unwrap_or(config.json_rpc_url); - let rpc_banks_url = Config::compute_rpc_banks_url(&json_rpc_url); - let url = Url::parse(&rpc_banks_url)?; - let host_port = (url.host_str().unwrap(), url.port().unwrap()); - - let runtime = Runtime::new().unwrap(); - let mut banks_client = runtime.block_on(start_tcp_client(&host_port))?; + let client = RpcClient::new(json_rpc_url); match command_args.command { Command::DistributeTokens(mut args) => { - runtime.block_on(spl_token::update_token_args( - &mut banks_client, - &mut args.spl_token_args, - ))?; - runtime.block_on(commands::process_allocations(&mut banks_client, &args))?; + spl_token::update_token_args(&client, &mut args.spl_token_args)?; + commands::process_allocations(&client, &args)?; } Command::Balances(mut args) => { - runtime.block_on(spl_token::update_decimals( - &mut banks_client, - &mut args.spl_token_args, - ))?; - runtime.block_on(commands::process_balances(&mut banks_client, &args))?; + spl_token::update_decimals(&client, &mut args.spl_token_args)?; + commands::process_balances(&client, &args)?; } Command::TransactionLog(args) => { commands::process_transaction_log(&args)?; diff --git a/tokens/src/spl_token.rs b/tokens/src/spl_token.rs index b77ea96a17..bc9aa2a45f 100644 --- a/tokens/src/spl_token.rs +++ b/tokens/src/spl_token.rs @@ -6,7 +6,7 @@ use console::style; use solana_account_decoder::parse_token::{ pubkey_from_spl_token_v2_0, spl_token_v2_0_pubkey, token_amount_to_ui_amount, }; -use solana_banks_client::{BanksClient, BanksClientExt}; +use solana_client::rpc_client::RpcClient; use solana_sdk::{instruction::Instruction, native_token::lamports_to_sol}; use solana_transaction_status::parse_token::spl_token_v2_0_instruction; use spl_associated_token_account_v1_0::{ @@ -17,32 +17,22 @@ use spl_token_v2_0::{ state::{Account as SplTokenAccount, Mint}, }; -pub async fn update_token_args( - client: &mut BanksClient, - args: &mut Option, -) -> Result<(), Error> { +pub fn update_token_args(client: &RpcClient, args: &mut Option) -> Result<(), Error> { if let Some(spl_token_args) = args { let sender_account = client - .get_account(spl_token_args.token_account_address) - .await? + .get_account(&spl_token_args.token_account_address) .unwrap_or_default(); let mint_address = pubkey_from_spl_token_v2_0(&SplTokenAccount::unpack(&sender_account.data)?.mint); spl_token_args.mint = mint_address; - update_decimals(client, args).await?; + update_decimals(client, args)?; } Ok(()) } -pub async fn update_decimals( - client: &mut BanksClient, - args: &mut Option, -) -> Result<(), Error> { +pub fn update_decimals(client: &RpcClient, args: &mut Option) -> Result<(), Error> { if let Some(spl_token_args) = args { - let mint_account = client - .get_account(spl_token_args.mint) - .await? - .unwrap_or_default(); + let mint_account = client.get_account(&spl_token_args.mint).unwrap_or_default(); let mint = Mint::unpack(&mint_account.data)?; spl_token_args.decimals = mint.decimals; } @@ -93,10 +83,10 @@ pub fn build_spl_token_instructions( instructions } -pub async fn check_spl_token_balances( +pub fn check_spl_token_balances( num_signatures: usize, allocations: &[Allocation], - client: &mut BanksClient, + client: &RpcClient, args: &DistributeTokensArgs, created_accounts: u64, ) -> Result<(), Error> { @@ -106,16 +96,16 @@ pub async fn check_spl_token_balances( .expect("spl_token_args must be some"); let allocation_amount: u64 = allocations.iter().map(|x| x.amount).sum(); - let (fee_calculator, _blockhash, _last_valid_slot) = client.get_fees().await?; + let fee_calculator = client.get_recent_blockhash()?.1; let fees = fee_calculator .lamports_per_signature .checked_mul(num_signatures as u64) .unwrap(); - let rent = client.get_rent().await?; - let token_account_rent_exempt_balance = rent.minimum_balance(SplTokenAccount::LEN); + let token_account_rent_exempt_balance = + client.get_minimum_balance_for_rent_exemption(SplTokenAccount::LEN)?; let account_creation_amount = created_accounts * token_account_rent_exempt_balance; - let fee_payer_balance = client.get_balance(args.fee_payer.pubkey()).await?; + let fee_payer_balance = client.get_balance(&args.fee_payer.pubkey())?; if fee_payer_balance < fees + account_creation_amount { return Err(Error::InsufficientFunds( vec![FundingSource::FeePayer].into(), @@ -123,8 +113,7 @@ pub async fn check_spl_token_balances( )); } let source_token_account = client - .get_account(spl_token_args.token_account_address) - .await? + .get_account(&spl_token_args.token_account_address) .unwrap_or_default(); let source_token = SplTokenAccount::unpack(&source_token_account.data)?; if source_token.amount < allocation_amount { @@ -136,8 +125,8 @@ pub async fn check_spl_token_balances( Ok(()) } -pub async fn print_token_balances( - client: &mut BanksClient, +pub fn print_token_balances( + client: &RpcClient, allocation: &Allocation, spl_token_args: &SplTokenArgs, ) -> Result<(), Error> { @@ -148,8 +137,7 @@ pub async fn print_token_balances( &spl_token_v2_0_pubkey(&spl_token_args.mint), ); let recipient_account = client - .get_account(pubkey_from_spl_token_v2_0(&associated_token_address)) - .await? + .get_account(&pubkey_from_spl_token_v2_0(&associated_token_address)) .unwrap_or_default(); let (actual, difference) = if let Ok(recipient_token) = SplTokenAccount::unpack(&recipient_account.data) @@ -188,498 +176,15 @@ pub async fn print_token_balances( #[cfg(test)] mod tests { - use super::*; - use crate::{ - commands::{process_allocations, tests::tmp_file_path, Allocation}, - db::{self, check_output_file}, - }; - use solana_account_decoder::parse_token::{spl_token_id_v2_0, spl_token_v2_0_pubkey}; - use solana_program_test::*; - use solana_sdk::{ - hash::Hash, - signature::{read_keypair_file, write_keypair_file, Keypair, Signer}, - system_instruction, - transaction::Transaction, - }; - use solana_transaction_status::parse_token::spl_token_v2_0_instruction; - use spl_associated_token_account_v1_0::{ - create_associated_token_account, get_associated_token_address, - }; - use spl_token_v2_0::{ - instruction::{initialize_account, initialize_mint, mint_to}, - solana_program::pubkey::Pubkey, - }; - use tempfile::{tempdir, NamedTempFile}; - - fn program_test() -> ProgramTest { - // Add SPL Associated Token program - let mut pc = ProgramTest::new( - "spl_associated_token_account", - pubkey_from_spl_token_v2_0(&spl_associated_token_account_v1_0::id()), - None, - ); - // Add SPL Token program - pc.add_program("spl_token", spl_token_id_v2_0(), None); - pc - } - - async fn initialize_test_mint( - banks_client: &mut BanksClient, - fee_payer: &Keypair, - mint: &Keypair, - decimals: u8, - recent_blockhash: Hash, - ) { - let rent = banks_client.get_rent().await.unwrap(); - let expected_mint_balance = rent.minimum_balance(Mint::LEN); - let instructions = vec![ - system_instruction::create_account( - &fee_payer.pubkey(), - &mint.pubkey(), - expected_mint_balance, - Mint::LEN as u64, - &spl_token_id_v2_0(), - ), - spl_token_v2_0_instruction( - initialize_mint( - &spl_token_v2_0::id(), - &spl_token_v2_0_pubkey(&mint.pubkey()), - &spl_token_v2_0_pubkey(&mint.pubkey()), - None, - decimals, - ) - .unwrap(), - ), - ]; - let mut transaction = Transaction::new_with_payer(&instructions, Some(&fee_payer.pubkey())); - transaction.sign(&[fee_payer, mint], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - } - - async fn initialize_token_account( - banks_client: &mut BanksClient, - fee_payer: &Keypair, - sender_account: &Keypair, - mint: &Keypair, - owner: &Keypair, - recent_blockhash: Hash, - ) { - let rent = banks_client.get_rent().await.unwrap(); - let expected_token_account_balance = rent.minimum_balance(SplTokenAccount::LEN); - let instructions = vec![ - system_instruction::create_account( - &fee_payer.pubkey(), - &sender_account.pubkey(), - expected_token_account_balance, - SplTokenAccount::LEN as u64, - &spl_token_id_v2_0(), - ), - spl_token_v2_0_instruction( - initialize_account( - &spl_token_v2_0::id(), - &spl_token_v2_0_pubkey(&sender_account.pubkey()), - &spl_token_v2_0_pubkey(&mint.pubkey()), - &spl_token_v2_0_pubkey(&owner.pubkey()), - ) - .unwrap(), - ), - ]; - let mut transaction = Transaction::new_with_payer(&instructions, Some(&fee_payer.pubkey())); - transaction.sign(&[fee_payer, sender_account], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - } - - async fn mint_to_account( - banks_client: &mut BanksClient, - fee_payer: &Keypair, - sender_account: &Keypair, - mint: &Keypair, - recent_blockhash: Hash, - ) { - let instructions = vec![spl_token_v2_0_instruction( - mint_to( - &spl_token_v2_0::id(), - &spl_token_v2_0_pubkey(&mint.pubkey()), - &spl_token_v2_0_pubkey(&sender_account.pubkey()), - &spl_token_v2_0_pubkey(&mint.pubkey()), - &[], - 200_000, - ) - .unwrap(), - )]; - let mut transaction = Transaction::new_with_payer(&instructions, Some(&fee_payer.pubkey())); - transaction.sign(&[fee_payer, mint], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - } - - async fn test_process_distribute_spl_tokens_with_client( - banks_client: &mut BanksClient, - fee_payer: Keypair, - transfer_amount: Option, - recent_blockhash: Hash, - ) { - // Initialize Token Mint - let decimals = 2; - let mint = Keypair::new(); - initialize_test_mint(banks_client, &fee_payer, &mint, decimals, recent_blockhash).await; - - // Initialize Sender Token Account and Mint - let sender_account = Keypair::new(); - let owner = Keypair::new(); - initialize_token_account( - banks_client, - &fee_payer, - &sender_account, - &mint, - &owner, - recent_blockhash, - ) - .await; - - mint_to_account( - banks_client, - &fee_payer, - &sender_account, - &mint, - recent_blockhash, - ) - .await; - - // Initialize one recipient Associated Token Account - let wallet_address_0 = Pubkey::new_unique(); - let instructions = vec![spl_token_v2_0_instruction(create_associated_token_account( - &spl_token_v2_0_pubkey(&fee_payer.pubkey()), - &wallet_address_0, - &spl_token_v2_0_pubkey(&mint.pubkey()), - ))]; - let mut transaction = Transaction::new_with_payer(&instructions, Some(&fee_payer.pubkey())); - transaction.sign(&[&fee_payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - let wallet_address_1 = Pubkey::new_unique(); - - // Create allocations csv - let allocation_amount = if let Some(amount) = transfer_amount { - amount - } else { - 100_000 - }; - let allocations_file = NamedTempFile::new().unwrap(); - let input_csv = allocations_file.path().to_str().unwrap().to_string(); - let mut wtr = csv::WriterBuilder::new().from_writer(allocations_file); - wtr.write_record(&["recipient", "amount"]).unwrap(); - wtr.write_record(&[wallet_address_0.to_string(), allocation_amount.to_string()]) - .unwrap(); - wtr.write_record(&[wallet_address_1.to_string(), allocation_amount.to_string()]) - .unwrap(); - wtr.flush().unwrap(); - - let dir = tempdir().unwrap(); - let transaction_db = dir - .path() - .join("transactions.db") - .to_str() - .unwrap() - .to_string(); - - let output_file = NamedTempFile::new().unwrap(); - let output_path = output_file.path().to_str().unwrap().to_string(); - - let args = DistributeTokensArgs { - sender_keypair: Box::new(owner), - fee_payer: Box::new(fee_payer), - dry_run: false, - input_csv, - transaction_db: transaction_db.clone(), - output_path: Some(output_path.clone()), - stake_args: None, - spl_token_args: Some(SplTokenArgs { - token_account_address: sender_account.pubkey(), - mint: mint.pubkey(), - decimals, - }), - transfer_amount, - }; - - // Distribute Allocations - let confirmations = process_allocations(banks_client, &args).await.unwrap(); - assert_eq!(confirmations, None); - - let associated_token_address_0 = - get_associated_token_address(&wallet_address_0, &spl_token_v2_0_pubkey(&mint.pubkey())); - let associated_token_address_1 = - get_associated_token_address(&wallet_address_1, &spl_token_v2_0_pubkey(&mint.pubkey())); - - let transaction_infos = - db::read_transaction_infos(&db::open_db(&transaction_db, true).unwrap()); - assert_eq!(transaction_infos.len(), 2); - assert!(transaction_infos - .iter() - .any(|info| info.recipient == pubkey_from_spl_token_v2_0(&wallet_address_0))); - assert!(transaction_infos - .iter() - .any(|info| info.recipient == pubkey_from_spl_token_v2_0(&wallet_address_1))); - assert_eq!(transaction_infos[0].amount, allocation_amount); - assert_eq!(transaction_infos[1].amount, allocation_amount); - - let recipient_account_0 = banks_client - .get_account(pubkey_from_spl_token_v2_0(&associated_token_address_0)) - .await - .unwrap() - .unwrap_or_default(); - assert_eq!( - SplTokenAccount::unpack(&recipient_account_0.data) - .unwrap() - .amount, - allocation_amount, - ); - let recipient_account_1 = banks_client - .get_account(pubkey_from_spl_token_v2_0(&associated_token_address_1)) - .await - .unwrap() - .unwrap_or_default(); - assert_eq!( - SplTokenAccount::unpack(&recipient_account_1.data) - .unwrap() - .amount, - allocation_amount, - ); - - check_output_file(&output_path, &db::open_db(&transaction_db, true).unwrap()); - - // Now, run it again, and check there's no double-spend. - process_allocations(banks_client, &args).await.unwrap(); - let transaction_infos = - db::read_transaction_infos(&db::open_db(&transaction_db, true).unwrap()); - assert_eq!(transaction_infos.len(), 2); - assert!(transaction_infos - .iter() - .any(|info| info.recipient == pubkey_from_spl_token_v2_0(&wallet_address_0))); - assert!(transaction_infos - .iter() - .any(|info| info.recipient == pubkey_from_spl_token_v2_0(&wallet_address_1))); - assert_eq!(transaction_infos[0].amount, allocation_amount); - assert_eq!(transaction_infos[1].amount, allocation_amount); - - let recipient_account_0 = banks_client - .get_account(pubkey_from_spl_token_v2_0(&associated_token_address_0)) - .await - .unwrap() - .unwrap_or_default(); - assert_eq!( - SplTokenAccount::unpack(&recipient_account_0.data) - .unwrap() - .amount, - allocation_amount, - ); - let recipient_account_1 = banks_client - .get_account(pubkey_from_spl_token_v2_0(&associated_token_address_1)) - .await - .unwrap() - .unwrap_or_default(); - assert_eq!( - SplTokenAccount::unpack(&recipient_account_1.data) - .unwrap() - .amount, - allocation_amount, - ); - - check_output_file(&output_path, &db::open_db(&transaction_db, true).unwrap()); - } - - #[tokio::test] - async fn test_process_spl_token_allocations() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - test_process_distribute_spl_tokens_with_client( - &mut banks_client, - payer, - None, - recent_blockhash, - ) - .await; - } - - #[tokio::test] - async fn test_process_spl_token_transfer_amount_allocations() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - test_process_distribute_spl_tokens_with_client( - &mut banks_client, - payer, - Some(10550), - recent_blockhash, - ) - .await; - } - - #[tokio::test] - async fn test_check_check_spl_token_balances() { - let (mut banks_client, payer, recent_blockhash) = program_test().start().await; - - let (fee_calculator, _, _) = banks_client.get_fees().await.unwrap(); - let signatures = 2; - let fees = fee_calculator.lamports_per_signature * signatures; - let fees_in_sol = lamports_to_sol(fees); - - let rent = banks_client.get_rent().await.unwrap(); - let expected_token_account_balance = rent.minimum_balance(SplTokenAccount::LEN); - let expected_token_account_balance_sol = lamports_to_sol(expected_token_account_balance); - - // Initialize Token Mint - let decimals = 2; - let mint = Keypair::new(); - initialize_test_mint(&mut banks_client, &payer, &mint, decimals, recent_blockhash).await; - - // Initialize Sender Token Account and Mint - let sender_account = Keypair::new(); - let owner = Keypair::new(); - let owner_keypair_file = tmp_file_path("keypair_file", &owner.pubkey()); - write_keypair_file(&owner, &owner_keypair_file).unwrap(); - - initialize_token_account( - &mut banks_client, - &payer, - &sender_account, - &mint, - &owner, - recent_blockhash, - ) - .await; - - let unfunded_fee_payer = Keypair::new(); - - let allocation_amount = 4200; - let allocations = vec![Allocation { - recipient: Pubkey::new_unique().to_string(), - amount: allocation_amount, - lockup_date: "".to_string(), - }]; - let mut args = DistributeTokensArgs { - sender_keypair: read_keypair_file(&owner_keypair_file).unwrap().into(), - fee_payer: Box::new(unfunded_fee_payer), - dry_run: false, - input_csv: "".to_string(), - transaction_db: "".to_string(), - output_path: None, - stake_args: None, - spl_token_args: Some(SplTokenArgs { - token_account_address: sender_account.pubkey(), - mint: mint.pubkey(), - decimals, - }), - transfer_amount: None, - }; - - // Unfunded fee_payer - let err_result = check_spl_token_balances( - signatures as usize, - &allocations, - &mut banks_client, - &args, - 1, - ) - .await - .unwrap_err(); - if let Error::InsufficientFunds(sources, amount) = err_result { - assert_eq!(sources, vec![FundingSource::FeePayer].into()); - assert!( - (amount - (fees_in_sol + expected_token_account_balance_sol)).abs() < f64::EPSILON - ); - } else { - panic!("check_spl_token_balances should have errored"); - } - - // Unfunded sender SPL Token account - let fee_payer = Keypair::new(); - - let instruction = system_instruction::transfer( - &payer.pubkey(), - &fee_payer.pubkey(), - fees + expected_token_account_balance, - ); - let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - args.fee_payer = Box::new(fee_payer); - let err_result = check_spl_token_balances( - signatures as usize, - &allocations, - &mut banks_client, - &args, - 1, - ) - .await - .unwrap_err(); - if let Error::InsufficientFunds(sources, amount) = err_result { - assert_eq!(sources, vec![FundingSource::SplTokenAccount].into()); - assert!( - (amount - token_amount_to_ui_amount(allocation_amount, decimals).ui_amount).abs() - < f64::EPSILON - ); - } else { - panic!("check_spl_token_balances should have errored"); - } - - // Fully funded payers - mint_to_account( - &mut banks_client, - &payer, - &sender_account, - &mint, - recent_blockhash, - ) - .await; - - check_spl_token_balances( - signatures as usize, - &allocations, - &mut banks_client, - &args, - 1, - ) - .await - .unwrap(); - - // Partially-funded fee payer can afford fees, but not to create Associated Token Account - let partially_funded_fee_payer = Keypair::new(); - - let instruction = system_instruction::transfer( - &payer.pubkey(), - &partially_funded_fee_payer.pubkey(), - fees, - ); - let mut transaction = Transaction::new_with_payer(&[instruction], Some(&payer.pubkey())); - transaction.sign(&[&payer], recent_blockhash); - banks_client.process_transaction(transaction).await.unwrap(); - - args.fee_payer = Box::new(partially_funded_fee_payer); - let err_result = check_spl_token_balances( - signatures as usize, - &allocations, - &mut banks_client, - &args, - 1, - ) - .await - .unwrap_err(); - if let Error::InsufficientFunds(sources, amount) = err_result { - assert_eq!(sources, vec![FundingSource::FeePayer].into()); - assert!( - (amount - (fees_in_sol + expected_token_account_balance_sol)).abs() < f64::EPSILON - ); - } else { - panic!("check_spl_token_balances should have errored"); - } - - // Succeeds if no account creation required - check_spl_token_balances( - signatures as usize, - &allocations, - &mut banks_client, - &args, - 0, - ) - .await - .unwrap(); - } + // The following unit tests were written for v1.4 using the ProgramTest framework, passing its + // BanksClient into the `solana-tokens` methods. With the revert to RpcClient in this module + // (https://github.com/solana-labs/solana/pull/13623), that approach was no longer viable. + // These tests were removed rather than rewritten to avoid accruing technical debt. Once a new + // rpc/client framework is implemented, they should be restored. + // + // async fn test_process_spl_token_allocations() + // async fn test_process_spl_token_transfer_amount_allocations() + // async fn test_check_spl_token_balances() + // + // https://github.com/solana-labs/solana/blob/5511d52c6284013a24ced10966d11d8f4585799e/tokens/src/spl_token.rs#L490-L685 } diff --git a/tokens/tests/commands.rs b/tokens/tests/commands.rs index 52de12e810..0d3d288bc9 100644 --- a/tokens/tests/commands.rs +++ b/tokens/tests/commands.rs @@ -1,8 +1,7 @@ -use solana_banks_client::start_tcp_client; +use solana_client::rpc_client::RpcClient; use solana_core::test_validator::TestValidator; use solana_tokens::commands::test_process_distribute_tokens_with_client; use std::fs::remove_dir_all; -use tokio::runtime::Runtime; #[test] fn test_process_distribute_with_rpc_client() { @@ -15,10 +14,8 @@ fn test_process_distribute_with_rpc_client() { .. } = TestValidator::run(); - Runtime::new().unwrap().block_on(async { - let mut banks_client = start_tcp_client(leader_data.rpc_banks).await.unwrap(); - test_process_distribute_tokens_with_client(&mut banks_client, alice, None).await - }); + let client = RpcClient::new_socket(leader_data.rpc); + test_process_distribute_tokens_with_client(&client, alice, None); // Explicit cleanup, otherwise "pure virtual method called" crash in Docker server.close().unwrap();