From fcf14ea851a2ca9c592578635737c8b2aeb65b8d Mon Sep 17 00:00:00 2001 From: Britt Cyr Date: Mon, 26 Aug 2024 14:52:47 -0400 Subject: [PATCH] use retry in wrapper fixture (#16) --- programs/wrapper/tests/cases/batch_update.rs | 216 +++++++----------- .../wrapper/tests/program_test/fixtures.rs | 185 +++++++-------- 2 files changed, 157 insertions(+), 244 deletions(-) diff --git a/programs/wrapper/tests/cases/batch_update.rs b/programs/wrapper/tests/cases/batch_update.rs index c591e96b9..8ea620e0b 100644 --- a/programs/wrapper/tests/cases/batch_update.rs +++ b/programs/wrapper/tests/cases/batch_update.rs @@ -1,11 +1,10 @@ -use std::{cell::RefMut, mem::size_of, rc::Rc}; +use std::{mem::size_of, rc::Rc}; use hypertree::{get_helper, DataIndex, RBNode, TreeReadOperations, NIL}; use manifest::state::{constants::NO_EXPIRATION_LAST_VALID_SLOT, OrderType}; -use solana_program_test::{tokio, ProgramTestContext}; +use solana_program_test::tokio; use solana_sdk::{ account::Account, instruction::Instruction, pubkey::Pubkey, signature::Keypair, signer::Signer, - transaction::Transaction, }; use wrapper::{ instruction_builders::{batch_update_instruction, create_wrapper_instructions}, @@ -27,7 +26,6 @@ async fn wrapper_batch_update_test() -> anyhow::Result<()> { let payer: Pubkey = test_fixture.payer(); let payer_keypair: Keypair = test_fixture.payer_keypair().insecure_clone(); - let mut program_test_context: RefMut = test_fixture.context.borrow_mut(); // There is no order 0 for the cancel to get, but it will fail silently and continue on. let batch_update_ix: Instruction = batch_update_instruction( @@ -48,19 +46,13 @@ async fn wrapper_batch_update_test() -> anyhow::Result<()> { )], None, ); - let batch_update_tx: Transaction = { - Transaction::new_signed_with_payer( - &[batch_update_ix], - Some(&payer), - &[&payer_keypair], - program_test_context.get_new_latest_blockhash().await?, - ) - }; - - program_test_context - .banks_client - .process_transaction(batch_update_tx) - .await?; + send_tx_with_retry( + Rc::clone(&test_fixture.context), + &[batch_update_ix], + Some(&payer), + &[&payer_keypair], + ) + .await?; // Cancel and place, so we have enough funds for the second one. let batch_update_ix: Instruction = batch_update_instruction( @@ -81,19 +73,13 @@ async fn wrapper_batch_update_test() -> anyhow::Result<()> { )], None, ); - let batch_update_tx: Transaction = { - Transaction::new_signed_with_payer( - &[batch_update_ix], - Some(&payer), - &[&payer_keypair], - program_test_context.get_new_latest_blockhash().await?, - ) - }; - - program_test_context - .banks_client - .process_transaction(batch_update_tx) - .await?; + send_tx_with_retry( + Rc::clone(&test_fixture.context), + &[batch_update_ix], + Some(&payer), + &[&payer_keypair], + ) + .await?; Ok(()) } @@ -106,7 +92,6 @@ async fn wrapper_batch_update_reuse_client_order_id_test() -> anyhow::Result<()> let payer: Pubkey = test_fixture.payer(); let payer_keypair: Keypair = test_fixture.payer_keypair().insecure_clone(); - let mut program_test_context: RefMut = test_fixture.context.borrow_mut(); // All the orders have the same client order id. let batch_update_ix: Instruction = batch_update_instruction( @@ -169,19 +154,13 @@ async fn wrapper_batch_update_reuse_client_order_id_test() -> anyhow::Result<()> ], None, ); - let batch_update_tx: Transaction = { - Transaction::new_signed_with_payer( - &[batch_update_ix], - Some(&payer), - &[&payer_keypair], - program_test_context.get_new_latest_blockhash().await?, - ) - }; - - program_test_context - .banks_client - .process_transaction(batch_update_tx) - .await?; + send_tx_with_retry( + Rc::clone(&test_fixture.context), + &[batch_update_ix], + Some(&payer), + &[&payer_keypair], + ) + .await?; // Cancel order 0 which is all of them let batch_update_ix: Instruction = batch_update_instruction( @@ -193,22 +172,18 @@ async fn wrapper_batch_update_reuse_client_order_id_test() -> anyhow::Result<()> vec![], None, ); - let batch_update_tx: Transaction = { - Transaction::new_signed_with_payer( - &[batch_update_ix], - Some(&payer), - &[&payer_keypair], - program_test_context.get_new_latest_blockhash().await?, - ) - }; - - program_test_context - .banks_client - .process_transaction(batch_update_tx) - .await?; + send_tx_with_retry( + Rc::clone(&test_fixture.context), + &[batch_update_ix], + Some(&payer), + &[&payer_keypair], + ) + .await?; // Assert that there are no more orders on the book. - let mut wrapper_account: Account = program_test_context + let mut wrapper_account: Account = test_fixture + .context + .borrow_mut() .banks_client .get_account(test_fixture.wrapper.key) .await @@ -262,7 +237,7 @@ async fn sync_remove_test() -> anyhow::Result<()> { Some(&second_payer), &[&second_payer_keypair, &second_wrapper_keypair], ) - .await; + .await?; test_fixture .claim_seat_for_keypair_with_wrapper( @@ -279,8 +254,6 @@ async fn sync_remove_test() -> anyhow::Result<()> { ) .await?; - let mut program_test_context: RefMut = test_fixture.context.borrow_mut(); - let batch_update_ix: Instruction = batch_update_instruction( &test_fixture.market.key, &payer, @@ -299,19 +272,13 @@ async fn sync_remove_test() -> anyhow::Result<()> { )], None, ); - let batch_update_tx: Transaction = { - Transaction::new_signed_with_payer( - &[batch_update_ix], - Some(&payer), - &[&payer_keypair], - program_test_context.get_new_latest_blockhash().await?, - ) - }; - - program_test_context - .banks_client - .process_transaction(batch_update_tx) - .await?; + send_tx_with_retry( + Rc::clone(&test_fixture.context), + &[batch_update_ix], + Some(&payer), + &[&payer_keypair], + ) + .await?; let batch_update_ix: Instruction = batch_update_instruction( &test_fixture.market.key, @@ -331,19 +298,13 @@ async fn sync_remove_test() -> anyhow::Result<()> { )], None, ); - let batch_update_tx: Transaction = { - Transaction::new_signed_with_payer( - &[batch_update_ix], - Some(&second_payer), - &[&second_payer_keypair], - program_test_context.get_new_latest_blockhash().await?, - ) - }; - - program_test_context - .banks_client - .process_transaction(batch_update_tx) - .await?; + send_tx_with_retry( + Rc::clone(&test_fixture.context), + &[batch_update_ix], + Some(&second_payer), + &[&second_payer_keypair], + ) + .await?; let batch_update_ix: Instruction = batch_update_instruction( &test_fixture.market.key, @@ -354,22 +315,18 @@ async fn sync_remove_test() -> anyhow::Result<()> { vec![], None, ); - let batch_update_tx: Transaction = { - Transaction::new_signed_with_payer( - &[batch_update_ix], - Some(&payer), - &[&payer_keypair], - program_test_context.get_new_latest_blockhash().await?, - ) - }; - - program_test_context - .banks_client - .process_transaction(batch_update_tx) - .await?; + send_tx_with_retry( + Rc::clone(&test_fixture.context), + &[batch_update_ix], + Some(&payer), + &[&payer_keypair], + ) + .await?; // Assert that there are no more orders on the book. - let mut wrapper_account: Account = program_test_context + let mut wrapper_account: Account = test_fixture + .context + .borrow_mut() .banks_client .get_account(test_fixture.wrapper.key) .await @@ -405,7 +362,6 @@ async fn wrapper_batch_update_cancel_all_test() -> anyhow::Result<()> { let payer: Pubkey = test_fixture.payer(); let payer_keypair: Keypair = test_fixture.payer_keypair().insecure_clone(); - let mut program_test_context: RefMut = test_fixture.context.borrow_mut(); let batch_update_ix: Instruction = batch_update_instruction( &test_fixture.market.key, @@ -425,19 +381,13 @@ async fn wrapper_batch_update_cancel_all_test() -> anyhow::Result<()> { )], None, ); - let batch_update_tx: Transaction = { - Transaction::new_signed_with_payer( - &[batch_update_ix], - Some(&payer), - &[&payer_keypair], - program_test_context.get_new_latest_blockhash().await?, - ) - }; - - program_test_context - .banks_client - .process_transaction(batch_update_tx) - .await?; + send_tx_with_retry( + Rc::clone(&test_fixture.context), + &[batch_update_ix], + Some(&payer), + &[&payer_keypair], + ) + .await?; let batch_update_ix: Instruction = batch_update_instruction( &test_fixture.market.key, @@ -448,22 +398,18 @@ async fn wrapper_batch_update_cancel_all_test() -> anyhow::Result<()> { vec![], None, ); - let batch_update_tx: Transaction = { - Transaction::new_signed_with_payer( - &[batch_update_ix], - Some(&payer), - &[&payer_keypair], - program_test_context.get_new_latest_blockhash().await?, - ) - }; - - program_test_context - .banks_client - .process_transaction(batch_update_tx) - .await?; + send_tx_with_retry( + Rc::clone(&test_fixture.context), + &[batch_update_ix], + Some(&payer), + &[&payer_keypair], + ) + .await?; // Assert that there are no more orders on the book. - let mut wrapper_account: Account = program_test_context + let mut wrapper_account: Account = test_fixture + .context + .borrow_mut() .banks_client .get_account(test_fixture.wrapper.key) .await @@ -498,7 +444,6 @@ async fn wrapper_batch_update_trader_index_hint_test() -> anyhow::Result<()> { let payer: Pubkey = test_fixture.payer(); let payer_keypair: Keypair = test_fixture.payer_keypair().insecure_clone(); - let mut program_test_context: RefMut = test_fixture.context.borrow_mut(); let batch_update_ix: Instruction = batch_update_instruction( &test_fixture.market.key, @@ -518,16 +463,13 @@ async fn wrapper_batch_update_trader_index_hint_test() -> anyhow::Result<()> { )], Some(0), ); - let batch_update_tx: Transaction = Transaction::new_signed_with_payer( + send_tx_with_retry( + Rc::clone(&test_fixture.context), &[batch_update_ix], Some(&payer), &[&payer_keypair], - program_test_context.get_new_latest_blockhash().await?, - ); - program_test_context - .banks_client - .process_transaction(batch_update_tx) - .await?; + ) + .await?; Ok(()) } diff --git a/programs/wrapper/tests/program_test/fixtures.rs b/programs/wrapper/tests/program_test/fixtures.rs index 888f2099d..8ba73ff55 100644 --- a/programs/wrapper/tests/program_test/fixtures.rs +++ b/programs/wrapper/tests/program_test/fixtures.rs @@ -93,61 +93,48 @@ impl TestFixture { let sol_mint_f: MintFixture = MintFixture::new(Rc::clone(&context), Some(sol_keypair), Some(9)).await; - let mut context_cell: RefMut = context.borrow_mut(); - let payer_pubkey: &Pubkey = &context_cell.payer.pubkey(); + let payer_pubkey: Pubkey = context.borrow().payer.pubkey(); + let payer: Keypair = context.borrow().payer.insecure_clone(); let create_market_ixs: Vec = create_market_instructions( &market_keypair.pubkey(), &sol_mint_f.key, &usdc_mint_f.key, - payer_pubkey, + &payer_pubkey, ) .unwrap(); - let create_market_tx: Transaction = { - Transaction::new_signed_with_payer( - &create_market_ixs[..], - Some(payer_pubkey), - &[&context_cell.payer.insecure_clone(), &market_keypair], - context_cell.get_new_latest_blockhash().await.unwrap(), - ) - }; - - context_cell - .banks_client - .process_transaction(create_market_tx) - .await - .unwrap(); + send_tx_with_retry( + Rc::clone(&context), + &create_market_ixs[..], + Some(&payer_pubkey), + &[&payer.insecure_clone(), &market_keypair], + ) + .await + .unwrap(); // Now that market is created, we can make a market fixture. let market_fixture: MarketFixture = MarketFixture::new(Rc::clone(&context), market_keypair.pubkey()).await; let create_wrapper_ixs: Vec = - create_wrapper_instructions(payer_pubkey, payer_pubkey, &wrapper_keypair.pubkey()) + create_wrapper_instructions(&payer_pubkey, &payer_pubkey, &wrapper_keypair.pubkey()) .unwrap(); + send_tx_with_retry( + Rc::clone(&context), + &create_wrapper_ixs[..], + Some(&payer_pubkey), + &[&payer.insecure_clone(), &wrapper_keypair], + ) + .await + .unwrap(); - let create_wrapper_tx: Transaction = { - Transaction::new_signed_with_payer( - &create_wrapper_ixs[..], - Some(payer_pubkey), - &[&context_cell.payer.insecure_clone(), &wrapper_keypair], - context_cell.get_new_latest_blockhash().await.unwrap(), - ) - }; - - context_cell - .banks_client - .process_transaction(create_wrapper_tx) - .await - .unwrap(); let wrapper_fixture: WrapperFixture = WrapperFixture::new(Rc::clone(&context), wrapper_keypair.pubkey()).await; - drop(context_cell); let payer_sol_fixture: TokenAccountFixture = - TokenAccountFixture::new(Rc::clone(&context), &sol_mint_f.key, payer_pubkey).await; + TokenAccountFixture::new(Rc::clone(&context), &sol_mint_f.key, &payer_pubkey).await; let payer_usdc_fixture = - TokenAccountFixture::new(Rc::clone(&context), &usdc_mint_f.key, payer_pubkey).await; + TokenAccountFixture::new(Rc::clone(&context), &usdc_mint_f.key, &payer_pubkey).await; TestFixture { context: Rc::clone(&context), @@ -198,26 +185,20 @@ impl TestFixture { keypair: &Keypair, wrapper_state: &Pubkey, ) -> anyhow::Result<(), BanksClientError> { - let mut program_test_context: RefMut = self.context.borrow_mut(); let claim_seat_ix: Instruction = claim_seat_instruction( &self.market.key, &keypair.pubkey(), &keypair.pubkey(), wrapper_state, ); - let claim_seat_tx: Transaction = { - Transaction::new_signed_with_payer( - &[claim_seat_ix], - Some(&keypair.pubkey()), - &[keypair], - program_test_context.get_new_latest_blockhash().await?, - ) - }; - - program_test_context - .banks_client - .process_transaction(claim_seat_tx) - .await?; + send_tx_with_retry( + Rc::clone(&self.context), + &[claim_seat_ix], + Some(&keypair.pubkey()), + &[&keypair.insecure_clone()], + ) + .await + .unwrap(); Ok(()) } @@ -292,7 +273,6 @@ impl TestFixture { (&self.usdc_mint.key, trader_token_account) }; - let mut program_test_context: RefMut = self.context.borrow_mut(); let deposit_ix: Instruction = deposit_instruction( &self.market.key, &keypair.pubkey(), @@ -303,18 +283,14 @@ impl TestFixture { spl_token::id(), ); - let deposit_tx: Transaction = { - Transaction::new_signed_with_payer( - &[deposit_ix], - Some(&keypair.pubkey()), - &[keypair], - program_test_context.get_new_latest_blockhash().await?, - ) - }; - program_test_context - .banks_client - .process_transaction(deposit_tx) - .await?; + send_tx_with_retry( + Rc::clone(&self.context), + &[deposit_ix], + Some(&keypair.pubkey()), + &[&keypair.insecure_clone()], + ) + .await + .unwrap(); Ok(()) } @@ -372,7 +348,6 @@ impl TestFixture { (&self.usdc_mint.key, trader_token_account) }; - let mut context: RefMut = self.context.borrow_mut(); let withdraw_ix: Instruction = withdraw_instruction( &self.market.key, &keypair.pubkey(), @@ -383,19 +358,14 @@ impl TestFixture { spl_token::id(), ); - let withdraw_tx: Transaction = { - Transaction::new_signed_with_payer( - &[withdraw_ix], - Some(&keypair.pubkey()), - &[keypair], - context.get_new_latest_blockhash().await?, - ) - }; - - context - .banks_client - .process_transaction(withdraw_tx) - .await?; + send_tx_with_retry( + Rc::clone(&self.context), + &[withdraw_ix], + Some(&keypair.pubkey()), + &[&keypair.insecure_clone()], + ) + .await + .unwrap(); Ok(()) } } @@ -517,44 +487,42 @@ impl MintFixture { mint_keypair: Option, mint_decimals: Option, ) -> MintFixture { - let context_ref: Rc> = Rc::clone(&context); - let keypair: Keypair = mint_keypair.unwrap_or_else(Keypair::new); - let mut context: RefMut = context.borrow_mut(); + let payer_pubkey: Pubkey = context.borrow().payer.pubkey(); + let payer: Keypair = context.borrow().payer.insecure_clone(); + + let mint_keypair: Keypair = mint_keypair.unwrap_or_else(Keypair::new); - let rent: Rent = context.banks_client.get_rent().await.unwrap(); + let rent: Rent = context.borrow_mut().banks_client.get_rent().await.unwrap(); let init_account_ix: Instruction = create_account( - &context.payer.pubkey(), - &keypair.pubkey(), + &context.borrow().payer.pubkey(), + &mint_keypair.pubkey(), rent.minimum_balance(spl_token::state::Mint::LEN), spl_token::state::Mint::LEN as u64, &spl_token::id(), ); let init_mint_ix: Instruction = spl_token::instruction::initialize_mint( &spl_token::id(), - &keypair.pubkey(), - &context.payer.pubkey(), + &mint_keypair.pubkey(), + &context.borrow().payer.pubkey(), None, mint_decimals.unwrap_or(6), ) .unwrap(); - let initialize_mint_tx: Transaction = Transaction::new_signed_with_payer( + send_tx_with_retry( + Rc::clone(&context), &[init_account_ix, init_mint_ix], - Some(&context.payer.pubkey()), - &[&context.payer.insecure_clone(), &keypair], - context.get_new_latest_blockhash().await.unwrap(), - ); - - context - .banks_client - .process_transaction(initialize_mint_tx) - .await - .unwrap(); + Some(&payer_pubkey), + &[&mint_keypair.insecure_clone(), &payer], + ) + .await + .unwrap(); + let context_ref: Rc> = Rc::clone(&context); MintFixture { context: context_ref, - key: keypair.pubkey(), + key: mint_keypair.pubkey(), } } @@ -567,7 +535,8 @@ impl MintFixture { Some(&payer_keypair.pubkey()), &[&payer_keypair], ) - .await; + .await + .unwrap(); } fn make_mint_to_ix(&self, dest: &Pubkey, amount: u64) -> Instruction { @@ -622,18 +591,15 @@ impl TokenAccountFixture { owner_pk: &Pubkey, keypair: &Keypair, ) -> Self { - let mut program_test_context: RefMut = context.borrow_mut(); - - let rent: Rent = program_test_context.banks_client.get_rent().await.unwrap(); + let rent: Rent = context.borrow_mut().banks_client.get_rent().await.unwrap(); let instructions: [Instruction; 2] = Self::create_ixs( rent, mint_pk, - &program_test_context.payer.pubkey(), + &context.borrow().payer.pubkey(), owner_pk, keypair, ) .await; - drop(program_test_context); let payer_keypair: Keypair = context.borrow().payer.insecure_clone(); send_tx_with_retry( @@ -642,7 +608,8 @@ impl TokenAccountFixture { Some(&payer_keypair.pubkey()), &[&payer_keypair, keypair], ) - .await; + .await + .unwrap(); Self { key: keypair.pubkey(), @@ -659,14 +626,13 @@ impl TokenAccountFixture { } } -// TODO: Make the TestFixture use this. pub(crate) async fn send_tx_with_retry( context: Rc>, instructions: &[Instruction], payer: Option<&Pubkey>, signers: &[&Keypair], -) { - let mut context: std::cell::RefMut = context.borrow_mut(); +) -> Result<(), BanksClientError> { + let mut context: RefMut = context.borrow_mut(); loop { let blockhash_or: Result = context.get_new_latest_blockhash().await; @@ -686,10 +652,15 @@ pub(crate) async fn send_tx_with_retry( // Retry on rpc errors. continue; } + BanksClientError::Io(_io_err) => { + // Retry on io errors. + continue; + } _ => { println!("Unexpected error: {:?}", error); - assert!(false); + return Err(error); } } } + Ok(()) }