From 16b60028e126bb393792b709e842323dd8f839b2 Mon Sep 17 00:00:00 2001 From: godmodegalactus Date: Tue, 22 Oct 2024 17:44:59 +0200 Subject: [PATCH 1/5] Using libSVM for simulation --- Cargo.lock | 22 ++ programs/simulator/Cargo.toml | 2 + .../tests/cases/test_swap_from_dump.rs | 264 ++++++++++-------- 3 files changed, 174 insertions(+), 114 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b0cd8db..1ddf1ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3865,6 +3865,26 @@ version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +[[package]] +name = "litesvm" +version = "0.1.0" +source = "git+https://github.com/blockworks-foundation/litesvm.git?branch=v0.1.0+solana_1.7#4c884606289e484090be42a08b79dc3bc5f449f7" +dependencies = [ + "bincode", + "indexmap 2.2.6", + "itertools 0.12.1", + "log 0.4.21", + "solana-address-lookup-table-program", + "solana-bpf-loader-program", + "solana-compute-budget-program", + "solana-loader-v4-program", + "solana-program", + "solana-program-runtime", + "solana-sdk", + "solana-system-program", + "thiserror", +] + [[package]] name = "lock_api" version = "0.3.4" @@ -6763,11 +6783,13 @@ dependencies = [ "bincode", "bonfida-test-utils", "env_logger", + "litesvm", "log 0.4.21", "router-test-lib", "sha2 0.10.8", "solana-address-lookup-table-program", "solana-program", + "solana-program-runtime", "solana-program-test", "solana-sdk", "spl-associated-token-account 1.1.3", diff --git a/programs/simulator/Cargo.toml b/programs/simulator/Cargo.toml index ce37c56..c51b1e5 100644 --- a/programs/simulator/Cargo.toml +++ b/programs/simulator/Cargo.toml @@ -23,6 +23,7 @@ test-case = "*" tokio = "1.37.0" solana-address-lookup-table-program = "1.17" solana-program-test = "1.17" +solana-program-runtime = "1.17" solana-sdk = "1.17" spl-token = { version = "^3.0.0", features = ["no-entrypoint"] } spl-token-2022 = { version = "1.0.0", features = ["no-entrypoint"] } @@ -33,6 +34,7 @@ env_logger = "0.9.0" bincode = "1.3.3" sha2 = "0.10.8" base64 = "0.12.3" +litesvm = { git = "https://github.com/blockworks-foundation/litesvm.git", branch = "v0.1.0+solana_1.7" } [profile.test] inherits = "release" \ No newline at end of file diff --git a/programs/simulator/tests/cases/test_swap_from_dump.rs b/programs/simulator/tests/cases/test_swap_from_dump.rs index 6974809..0b3f114 100644 --- a/programs/simulator/tests/cases/test_swap_from_dump.rs +++ b/programs/simulator/tests/cases/test_swap_from_dump.rs @@ -1,27 +1,25 @@ -use anyhow::{Context, Error}; -use bonfida_test_utils::error::TestError; -use bonfida_test_utils::ProgramTestContextExt; -use log::{debug, error, info, warn}; +use anyhow::Error; +use litesvm::LiteSVM; +use log::{error, info, warn}; use router_test_lib::execution_dump::{ExecutionDump, ExecutionItem}; use router_test_lib::{execution_dump, serialize}; -use solana_program::clock::{Clock, Epoch}; +use solana_program::clock::Clock; use solana_program::instruction::Instruction; use solana_program::program_pack::Pack; use solana_program::program_stubs::{set_syscall_stubs, SyscallStubs}; use solana_program::pubkey::Pubkey; use solana_program::sysvar::SysvarId; -use solana_program_test::BanksClientError; -use solana_program_test::{ProgramTest, ProgramTestContext}; use solana_sdk::account::{Account, AccountSharedData, ReadableAccount}; -use solana_sdk::epoch_info::EpochInfo; +use solana_sdk::bpf_loader_upgradeable::UpgradeableLoaderState; +use solana_sdk::message::{Message, VersionedMessage}; use solana_sdk::signature::Keypair; use solana_sdk::signer::Signer; -use solana_sdk::transaction::Transaction; +use solana_sdk::transaction::VersionedTransaction; use spl_associated_token_account::get_associated_token_address; use spl_token::state::AccountState; use spl_token_2022::state::AccountState as AccountState2022; use std::collections::HashMap; -use std::process::exit; +use std::path::PathBuf; use std::str::FromStr; // use sha2::Sha256; // use sha2::Digest; @@ -79,7 +77,7 @@ async fn run_all_swap_from_dump(dump_name: &str) -> Result, Er let mut stop_at = u32::MAX; let skip_ixs_index = vec![]; - let mut run_lot_size = option_env!("RUN_LOT_SIZE") + let run_lot_size = option_env!("RUN_LOT_SIZE") .map(|x| u32::from_str(x).unwrap_or(500)) .unwrap_or(500); @@ -126,7 +124,7 @@ async fn run_all_swap_from_dump(dump_name: &str) -> Result, Er let instruction = deserialize_instruction("e.instruction)?; let programs = data.programs.iter().copied().collect(); - let mut ctx = setup_test_chain(&programs, &clock, &data).await; + let mut ctx = setup_test_chain(&programs, &clock, &data, &instruction.program_id)?; create_wallet(&mut ctx, wallet.pubkey()); @@ -157,7 +155,7 @@ async fn run_all_swap_from_dump(dump_name: &str) -> Result, Er .await?; for meta in &instruction.accounts { - let Ok(Some(account)) = ctx.banks_client.get_account(meta.pubkey).await else { + let Some(_account) = ctx.get_account(&meta.pubkey) else { log::warn!("missing account : {:?}", meta.pubkey); continue; }; @@ -278,7 +276,7 @@ async fn debug_print_ix( success: &mut i32, index: &mut u32, quote: &ExecutionItem, - ctx: &mut ProgramTestContext, + ctx: &mut LiteSVM, instruction: &Instruction, input_mint_is_2022: bool, output_mint_is_2022: bool, @@ -310,13 +308,8 @@ async fn debug_print_ix( for acc in &instruction.accounts { let account = ctx - .banks_client - .get_account(acc.pubkey) - .await - .map(|x| { - x.map(|y| (y.executable, y.owner.to_string())) - .unwrap_or((false, "???".to_string())) - }) + .get_account(&acc.pubkey) + .map(|x| (x.executable, x.owner.to_string())) .unwrap_or((false, "???".to_string())); warn!( @@ -341,14 +334,54 @@ fn deserialize_instruction(swap_ix: &Vec) -> anyhow::Result { Ok(instruction) } -async fn initialize_accounts( - program_test: &mut ProgramTest, +fn initialize_accounts( + program_test: &mut LiteSVM, dump: &ExecutionDump, + instruction_program: &Pubkey, ) -> anyhow::Result<()> { - println!("initializing accounts : {:?}", dump.accounts.len()); - for (pk, account) in &dump.accounts { - println!("Setting data for {}", pk); - program_test.add_account( + log::debug!("initializing accounts : {:?}", dump.accounts.len()); + let accounts_to_load = dump.accounts.clone(); + for (pk, account) in &accounts_to_load { + if *pk == *instruction_program { + continue; + } + if *account.owner() == solana_sdk::bpf_loader_upgradeable::ID { + log::debug!("{pk:?} has upgradable loader"); + let state = bincode::deserialize::(&account.data()).unwrap(); + if let UpgradeableLoaderState::Program { + programdata_address, + } = state + { + // load buffer accounts first + match accounts_to_load.get(&programdata_address) { + Some(program_buffer) => { + log::debug!("loading buffer: {programdata_address:?}"); + program_test.set_account( + programdata_address, + solana_sdk::account::Account { + lamports: program_buffer.lamports(), + owner: *program_buffer.owner(), + data: program_buffer.data().to_vec(), + rent_epoch: program_buffer.rent_epoch(), + executable: program_buffer.executable(), + }, + )?; + } + None => { + error!("{programdata_address:?} is not there"); + } + } + } + } + log::debug!( + "Setting data for {} with owner {} and is executable {}", + pk, + account.owner(), + account.executable() + ); + + log::debug!("Setting data for {}", pk); + program_test.set_account( *pk, solana_sdk::account::Account { lamports: account.lamports(), @@ -357,93 +390,84 @@ async fn initialize_accounts( rent_epoch: account.rent_epoch(), executable: account.executable(), }, - ); + )?; } Ok(()) } async fn simulate_cu_usage( - ctx: &mut ProgramTestContext, + ctx: &mut LiteSVM, owner: &Keypair, instruction: &Instruction, ) -> Option { - let mut transaction = - Transaction::new_with_payer(&[instruction.clone()], Some(&ctx.payer.pubkey())); - - transaction.sign(&[&ctx.payer, owner], ctx.last_blockhash); - let sim = ctx - .banks_client - .simulate_transaction(transaction.clone()) - .await; + let tx = VersionedTransaction::try_new( + VersionedMessage::Legacy(Message::new(&[instruction.clone()], Some(&owner.pubkey()))), + &[owner], + ) + .unwrap(); + + let sim = ctx.simulate_transaction(tx); match sim { Ok(sim) => { - log::debug!("{:?}", sim.result); - let simulation_details = sim.simulation_details.unwrap(); - let cus = simulation_details.units_consumed; - if sim.result.is_some() && sim.result.clone().unwrap().is_ok() { - log::debug!("units consumed : {}", cus); + let cus = sim.compute_units_consumed; + log::debug!("----logs"); + for log in sim.logs { + log::debug!("{log:?}"); + } + if cus > 0 { Some(cus) - } else if sim.result.is_some() && sim.result.clone().unwrap().is_err() { - log::debug!("simluation failed : {:?}", sim.result.unwrap()); - log::debug!("----logs"); - for log in simulation_details.logs { - log::debug!("{log:?}"); - } - None } else { None } } Err(e) => { - log::warn!("Error simulating : {}", e); + log::warn!("Error simulating : {:?}", e); None } } } -async fn swap( - ctx: &mut ProgramTestContext, - owner: &Keypair, - instruction: &Instruction, -) -> anyhow::Result<()> { - ctx.get_new_latest_blockhash().await?; - - log::info!("swapping"); - let result = ctx - .sign_send_instructions(&[instruction.clone()], &[&owner]) - .await; +async fn swap(ctx: &mut LiteSVM, owner: &Keypair, instruction: &Instruction) -> anyhow::Result<()> { + let tx = VersionedTransaction::try_new( + VersionedMessage::Legacy(Message::new(&[instruction.clone()], Some(&owner.pubkey()))), + &[owner], + ) + .unwrap(); + let result = ctx.send_transaction(tx); match result { - Ok(()) => Ok(()), - Err(e) => Err(anyhow::format_err!("Failed to swap {:?}", e)), + Ok(_) => Ok(()), + Err(e) => { + log::error!("------------- LOGS ------------------"); + for log in &e.meta.logs { + log::error!("{log:?}"); + } + Err(anyhow::format_err!("Failed to swap {:?}", e.err)) + }, } } async fn get_balance( - ctx: &mut ProgramTestContext, + ctx: &mut LiteSVM, owner: Pubkey, mint: Pubkey, is_2022: bool, ) -> anyhow::Result { let ata_address = get_associated_token_address(&owner, &mint); - if is_2022 { - let Ok(ata) = ctx.banks_client.get_account(ata_address).await else { - return Ok(0); - }; - - let Some(ata) = ata else { - return Ok(0); - }; + let Some(ata) = ctx.get_account(&ata_address) else { + return Ok(0); + }; + if is_2022 { let ata = spl_token_2022::state::Account::unpack(&ata.data); if let Ok(ata) = ata { return Ok(ata.amount); } }; - if let Ok(ata) = ctx.get_token_account(ata_address).await { + if let Ok(ata) = spl_token::state::Account::unpack(&ata.data) { Ok(ata.amount) } else { Ok(0u64) @@ -451,7 +475,7 @@ async fn get_balance( } async fn set_balance( - ctx: &mut ProgramTestContext, + ctx: &mut LiteSVM, owner: Pubkey, mint: Pubkey, amount: u64, @@ -474,15 +498,15 @@ async fn set_balance( account.pack_into_slice(data.as_mut_slice()); ctx.set_account( - &ata_address, - &AccountSharedData::from(Account { + ata_address, + Account { lamports: 1_000_000_000, data: data, owner: spl_token_2022::ID, executable: false, rent_epoch: 0, - }), - ); + }, + )?; return Ok(()); } @@ -501,37 +525,54 @@ async fn set_balance( account.pack_into_slice(data.as_mut_slice()); ctx.set_account( - &ata_address, - &AccountSharedData::from(Account { + ata_address, + Account { lamports: 1_000_000_000, data: data, owner: spl_token::ID, executable: false, rent_epoch: 0, - }), - ); + }, + )?; Ok(()) } -fn create_wallet(ctx: &mut ProgramTestContext, address: Pubkey) { - ctx.set_account( - &address, - &AccountSharedData::from(Account { - lamports: 1_000_000_000, - data: vec![], - owner: address, - executable: false, - rent_epoch: 0, - }), - ); +fn create_wallet(ctx: &mut LiteSVM, address: Pubkey) { + let _ = ctx.airdrop(&address, 1_000_000_000); +} + +pub fn find_file(filename: &str) -> Option { + for dir in default_shared_object_dirs() { + let candidate = dir.join(filename); + if candidate.exists() { + return Some(candidate); + } + } + None +} + +fn default_shared_object_dirs() -> Vec { + let mut search_path = vec![]; + if let Ok(bpf_out_dir) = std::env::var("BPF_OUT_DIR") { + search_path.push(PathBuf::from(bpf_out_dir)); + } else if let Ok(bpf_out_dir) = std::env::var("SBF_OUT_DIR") { + search_path.push(PathBuf::from(bpf_out_dir)); + } + search_path.push(PathBuf::from("tests/fixtures")); + if let Ok(dir) = std::env::current_dir() { + search_path.push(dir); + } + log::trace!("SBF .so search path: {:?}", search_path); + search_path } -async fn setup_test_chain( - programs: &Vec, +fn setup_test_chain( + _programs: &Vec, clock: &Clock, dump: &ExecutionDump, -) -> ProgramTestContext { + instruction_program: &Pubkey, +) -> anyhow::Result { // We need to intercept logs to capture program log output let log_filter = "solana_rbpf=trace,\ solana_runtime::message_processor=debug,\ @@ -546,27 +587,22 @@ async fn setup_test_chain( .build(); let _ = log::set_boxed_logger(Box::new(env_logger)); - let mut program_test = ProgramTest::default(); + let mut program_test = LiteSVM::new(); + program_test.set_sysvar(clock); - initialize_accounts(&mut program_test, dump).await.unwrap(); + initialize_accounts(&mut program_test, dump, instruction_program)?; + let path = find_file(format!("autobahn_executor.so").as_str()).unwrap(); + log::debug!("Adding program: {:?} at {path:?}", autobahn_executor::ID); + program_test.add_program_from_file(autobahn_executor::ID, path)?; - program_test.prefer_bpf(true); - for &key in programs { - program_test.add_program(key.to_string().as_str(), key, None); - } - program_test.add_program("autobahn_executor", autobahn_executor::ID, None); + let path = find_file(format!("{instruction_program:?}.so").as_str()).unwrap(); + log::debug!("Adding program: {:?} at {path:?}", instruction_program); + program_test.add_program_from_file(*instruction_program, path)?; // TODO: make this dynamic based on routes - program_test.set_compute_max_units(1_400_000); - - let mut program_test_context = program_test.start_with_context().await; - - // Set clock - program_test_context.set_sysvar(clock); - - info!("Setting clock to: {}", clock.unix_timestamp); - - program_test_context.warp_to_slot(40).unwrap(); + let mut cb = solana_program_runtime::compute_budget::ComputeBudget::default(); + cb.compute_unit_limit = 1_400_000; + program_test.set_compute_budget(cb); - program_test_context + Ok(program_test) } From 8dd6e978d7ca5a7cba66ae228a41e526a574d32d Mon Sep 17 00:00:00 2001 From: godmodegalactus Date: Thu, 24 Oct 2024 17:04:43 +0200 Subject: [PATCH 2/5] Some more fixes for invalid mint authority --- .../src/test_tools/generate_dex_rpc_dump.rs | 11 +- .../tests/cases/test_swap_from_dump.rs | 109 ++++++++---------- 2 files changed, 52 insertions(+), 68 deletions(-) diff --git a/lib/router-lib/src/test_tools/generate_dex_rpc_dump.rs b/lib/router-lib/src/test_tools/generate_dex_rpc_dump.rs index e3720da..1133986 100644 --- a/lib/router-lib/src/test_tools/generate_dex_rpc_dump.rs +++ b/lib/router-lib/src/test_tools/generate_dex_rpc_dump.rs @@ -126,7 +126,7 @@ pub async fn run_dump_mainnet_data_with_custom_amount( } let accounts = rpc_client.get_multiple_accounts(&accounts_needed).await?; - for (_, account) in accounts { + for (_pk, account) in accounts { // get buffer for upgradable programs if account.owner == solana_sdk::bpf_loader_upgradeable::ID { let state = bincode::deserialize::(&account.data).unwrap(); @@ -260,7 +260,7 @@ pub async fn run_dump_swap_ix_with_custom_amount( dump.accounts .insert(id.input_mint(), account.account.clone()); let account = chain_data_reader - .account(&id.input_mint()) + .account(&id.output_mint()) .expect("missing mint"); dump.accounts .insert(id.output_mint(), account.account.clone()); @@ -307,9 +307,6 @@ pub async fn run_dump_swap_ix_with_custom_amount( instruction: bincode::serialize(&swap_exact_out_ix.instruction).unwrap(), is_exact_out: true, }); - - // add exact out accounts - let chain_data_reader = chain_data.read().unwrap(); for account in swap_exact_out_ix.instruction.accounts { if let Ok(acc) = chain_data_reader.account(&account.pubkey) { dump.accounts.insert(account.pubkey, acc.account.clone()); @@ -351,9 +348,9 @@ pub async fn run_dump_swap_ix_with_custom_amount( debug!("program : {program:?}"); } - for (pk, program) in &dump.accounts { + for (pk, account_data) in &dump.accounts { let mut hasher = Sha256::new(); - hasher.update(program.data()); + hasher.update(account_data.data()); let result = hasher.finalize(); let base64 = base64::encode(result); debug!("account : {pk:?} dump : {base64:?}"); diff --git a/programs/simulator/tests/cases/test_swap_from_dump.rs b/programs/simulator/tests/cases/test_swap_from_dump.rs index 0b3f114..d7b5bc4 100644 --- a/programs/simulator/tests/cases/test_swap_from_dump.rs +++ b/programs/simulator/tests/cases/test_swap_from_dump.rs @@ -3,6 +3,8 @@ use litesvm::LiteSVM; use log::{error, info, warn}; use router_test_lib::execution_dump::{ExecutionDump, ExecutionItem}; use router_test_lib::{execution_dump, serialize}; +use sha2::Digest; +use sha2::Sha256; use solana_program::clock::Clock; use solana_program::instruction::Instruction; use solana_program::program_pack::Pack; @@ -15,14 +17,14 @@ use solana_sdk::message::{Message, VersionedMessage}; use solana_sdk::signature::Keypair; use solana_sdk::signer::Signer; use solana_sdk::transaction::VersionedTransaction; -use spl_associated_token_account::get_associated_token_address; +use spl_associated_token_account::{ + get_associated_token_address, get_associated_token_address_with_program_id, +}; use spl_token::state::AccountState; use spl_token_2022::state::AccountState as AccountState2022; use std::collections::HashMap; use std::path::PathBuf; use std::str::FromStr; -// use sha2::Sha256; -// use sha2::Digest; struct TestLogSyscallStubs; impl SyscallStubs for TestLogSyscallStubs { @@ -143,28 +145,31 @@ async fn run_all_swap_from_dump(dump_name: &str) -> Result, Er quote.input_mint, initial_in_balance, input_mint_is_2022, - ) - .await?; + )?; set_balance( &mut ctx, wallet.pubkey(), quote.output_mint, initial_out_balance, output_mint_is_2022, - ) - .await?; + )?; for meta in &instruction.accounts { - let Some(_account) = ctx.get_account(&meta.pubkey) else { + let Some(account) = ctx.get_account(&meta.pubkey) else { log::warn!("missing account : {:?}", meta.pubkey); continue; }; + // keep code to test hashses - // let mut hasher = Sha256::new(); - // hasher.update(account.data()); - // let result = hasher.finalize(); - // let base64 = base64::encode(result); - // log::debug!("account : {:?} dump : {base64:?} executable : {}", meta.pubkey, account.executable()); + let mut hasher = Sha256::new(); + hasher.update(account.data()); + let result = hasher.finalize(); + let base64 = base64::encode(result); + log::debug!( + "account : {:?} dump : {base64:?} executable : {}", + meta.pubkey, + account.executable() + ); } if let Some(cus) = simulate_cu_usage(&mut ctx, &wallet, &instruction).await { @@ -334,17 +339,10 @@ fn deserialize_instruction(swap_ix: &Vec) -> anyhow::Result { Ok(instruction) } -fn initialize_accounts( - program_test: &mut LiteSVM, - dump: &ExecutionDump, - instruction_program: &Pubkey, -) -> anyhow::Result<()> { +fn initialize_accounts(program_test: &mut LiteSVM, dump: &ExecutionDump) -> anyhow::Result<()> { log::debug!("initializing accounts : {:?}", dump.accounts.len()); let accounts_to_load = dump.accounts.clone(); for (pk, account) in &accounts_to_load { - if *pk == *instruction_program { - continue; - } if *account.owner() == solana_sdk::bpf_loader_upgradeable::ID { log::debug!("{pk:?} has upgradable loader"); let state = bincode::deserialize::(&account.data()).unwrap(); @@ -439,12 +437,12 @@ async fn swap(ctx: &mut LiteSVM, owner: &Keypair, instruction: &Instruction) -> match result { Ok(_) => Ok(()), Err(e) => { - log::error!("------------- LOGS ------------------"); + log::debug!("------------- LOGS ------------------"); for log in &e.meta.logs { - log::error!("{log:?}"); + log::debug!("{log:?}"); } Err(anyhow::format_err!("Failed to swap {:?}", e.err)) - }, + } } } @@ -474,17 +472,24 @@ async fn get_balance( } } -async fn set_balance( +fn set_balance( ctx: &mut LiteSVM, owner: Pubkey, mint: Pubkey, amount: u64, is_2022: bool, ) -> anyhow::Result<()> { - let ata_address = get_associated_token_address(&owner, &mint); + let token_program_id = if is_2022 { + spl_token_2022::ID + } else { + spl_token::ID + }; + + let ata_address = + get_associated_token_address_with_program_id(&owner, &mint, &token_program_id); + let mut data = vec![0u8; 165]; if is_2022 { - let mut data = vec![0u8; 165]; let account = spl_token_2022::state::Account { mint, owner, @@ -496,42 +501,28 @@ async fn set_balance( close_authority: Default::default(), }; account.pack_into_slice(data.as_mut_slice()); - - ctx.set_account( - ata_address, - Account { - lamports: 1_000_000_000, - data: data, - owner: spl_token_2022::ID, - executable: false, - rent_epoch: 0, - }, - )?; - - return Ok(()); - } - - let mut data = vec![0u8; 165]; - let account = spl_token::state::Account { - mint, - owner, - amount, - delegate: Default::default(), - state: AccountState::Initialized, - is_native: Default::default(), - delegated_amount: 0, - close_authority: Default::default(), + } else { + let account = spl_token::state::Account { + mint, + owner, + amount, + delegate: Default::default(), + state: AccountState::Initialized, + is_native: Default::default(), + delegated_amount: 0, + close_authority: Default::default(), + }; + account.pack_into_slice(data.as_mut_slice()); }; - account.pack_into_slice(data.as_mut_slice()); ctx.set_account( ata_address, Account { lamports: 1_000_000_000, data: data, - owner: spl_token::ID, + owner: token_program_id, executable: false, - rent_epoch: 0, + rent_epoch: u64::MAX, }, )?; @@ -571,7 +562,7 @@ fn setup_test_chain( _programs: &Vec, clock: &Clock, dump: &ExecutionDump, - instruction_program: &Pubkey, + _instruction_program: &Pubkey, ) -> anyhow::Result { // We need to intercept logs to capture program log output let log_filter = "solana_rbpf=trace,\ @@ -590,15 +581,11 @@ fn setup_test_chain( let mut program_test = LiteSVM::new(); program_test.set_sysvar(clock); - initialize_accounts(&mut program_test, dump, instruction_program)?; + initialize_accounts(&mut program_test, dump)?; let path = find_file(format!("autobahn_executor.so").as_str()).unwrap(); log::debug!("Adding program: {:?} at {path:?}", autobahn_executor::ID); program_test.add_program_from_file(autobahn_executor::ID, path)?; - let path = find_file(format!("{instruction_program:?}.so").as_str()).unwrap(); - log::debug!("Adding program: {:?} at {path:?}", instruction_program); - program_test.add_program_from_file(*instruction_program, path)?; - // TODO: make this dynamic based on routes let mut cb = solana_program_runtime::compute_budget::ComputeBudget::default(); cb.compute_unit_limit = 1_400_000; From fc2e08cceb16b901302c1106cca7ca7a68042eae Mon Sep 17 00:00:00 2001 From: godmodegalactus Date: Thu, 24 Oct 2024 17:56:02 +0200 Subject: [PATCH 3/5] avoiding disabled lst mints --- Cargo.lock | 2 ++ lib/dex-infinity/src/infinity.rs | 8 ++++++++ programs/simulator/Cargo.toml | 2 ++ programs/simulator/tests/cases/test_swap_from_dump.rs | 2 ++ 4 files changed, 14 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 1ddf1ca..8543c62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6797,6 +6797,8 @@ dependencies = [ "spl-token-2022 1.0.0", "test-case", "tokio", + "tracing", + "tracing-subscriber", ] [[package]] diff --git a/lib/dex-infinity/src/infinity.rs b/lib/dex-infinity/src/infinity.rs index 2917876..cb8b144 100644 --- a/lib/dex-infinity/src/infinity.rs +++ b/lib/dex-infinity/src/infinity.rs @@ -68,6 +68,14 @@ impl DexInterface for InfinityDex { let lst_mint = lst_data.sol_val_calc.lst_mint(); let account_metas = lst_data.sol_val_calc.ix_accounts(); let num_accounts_for_tx = account_metas.len(); + let Ok((lst_state, lst_data)) = amm.find_ready_lst(lst_mint) else { + continue; + }; + + if lst_state.is_input_disabled!= 0 { + continue; + } + for pk in lst_data.sol_val_calc.get_accounts_to_update() { let edges = vec![ Arc::new(InfinityEdgeIdentifier { diff --git a/programs/simulator/Cargo.toml b/programs/simulator/Cargo.toml index c51b1e5..98502f9 100644 --- a/programs/simulator/Cargo.toml +++ b/programs/simulator/Cargo.toml @@ -35,6 +35,8 @@ bincode = "1.3.3" sha2 = "0.10.8" base64 = "0.12.3" litesvm = { git = "https://github.com/blockworks-foundation/litesvm.git", branch = "v0.1.0+solana_1.7" } +tracing = "0.1.37" +tracing-subscriber = "0.3.16" [profile.test] inherits = "release" \ No newline at end of file diff --git a/programs/simulator/tests/cases/test_swap_from_dump.rs b/programs/simulator/tests/cases/test_swap_from_dump.rs index d7b5bc4..7971a46 100644 --- a/programs/simulator/tests/cases/test_swap_from_dump.rs +++ b/programs/simulator/tests/cases/test_swap_from_dump.rs @@ -73,6 +73,8 @@ async fn test_quote_match_swap_for_infinity() -> anyhow::Result<()> { } async fn run_all_swap_from_dump(dump_name: &str) -> Result, Error> { + tracing_subscriber::fmt::init(); + let mut skip_count = option_env!("SKIP_COUNT") .map(|x| u32::from_str(x).unwrap_or(0)) .unwrap_or(0); From 6e58ab1e26e585f921218a346c46cdb15e0b6225 Mon Sep 17 00:00:00 2001 From: godmodegalactus Date: Fri, 25 Oct 2024 11:58:16 +0200 Subject: [PATCH 4/5] performance improvements, reduced log-levels --- lib/dex-infinity/src/infinity.rs | 2 +- .../tests/cases/test_swap_from_dump.rs | 42 ++++++++----------- 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/lib/dex-infinity/src/infinity.rs b/lib/dex-infinity/src/infinity.rs index cb8b144..9f4012c 100644 --- a/lib/dex-infinity/src/infinity.rs +++ b/lib/dex-infinity/src/infinity.rs @@ -72,7 +72,7 @@ impl DexInterface for InfinityDex { continue; }; - if lst_state.is_input_disabled!= 0 { + if lst_state.is_input_disabled != 0 { continue; } diff --git a/programs/simulator/tests/cases/test_swap_from_dump.rs b/programs/simulator/tests/cases/test_swap_from_dump.rs index 7971a46..719c19c 100644 --- a/programs/simulator/tests/cases/test_swap_from_dump.rs +++ b/programs/simulator/tests/cases/test_swap_from_dump.rs @@ -128,7 +128,7 @@ async fn run_all_swap_from_dump(dump_name: &str) -> Result, Er let instruction = deserialize_instruction("e.instruction)?; let programs = data.programs.iter().copied().collect(); - let mut ctx = setup_test_chain(&programs, &clock, &data, &instruction.program_id)?; + let mut ctx = setup_test_chain(&programs, &clock, &data, &instruction)?; create_wallet(&mut ctx, wallet.pubkey()); @@ -341,10 +341,16 @@ fn deserialize_instruction(swap_ix: &Vec) -> anyhow::Result { Ok(instruction) } -fn initialize_accounts(program_test: &mut LiteSVM, dump: &ExecutionDump) -> anyhow::Result<()> { +fn initialize_accounts( + program_test: &mut LiteSVM, + dump: &ExecutionDump, + accounts_list: &Vec, +) -> anyhow::Result<()> { log::debug!("initializing accounts : {:?}", dump.accounts.len()); - let accounts_to_load = dump.accounts.clone(); - for (pk, account) in &accounts_to_load { + for pk in accounts_list { + let Some(account) = dump.accounts.get(pk) else { + continue; + }; if *account.owner() == solana_sdk::bpf_loader_upgradeable::ID { log::debug!("{pk:?} has upgradable loader"); let state = bincode::deserialize::(&account.data()).unwrap(); @@ -353,7 +359,7 @@ fn initialize_accounts(program_test: &mut LiteSVM, dump: &ExecutionDump) -> anyh } = state { // load buffer accounts first - match accounts_to_load.get(&programdata_address) { + match dump.accounts.get(&programdata_address) { Some(program_buffer) => { log::debug!("loading buffer: {programdata_address:?}"); program_test.set_account( @@ -439,9 +445,9 @@ async fn swap(ctx: &mut LiteSVM, owner: &Keypair, instruction: &Instruction) -> match result { Ok(_) => Ok(()), Err(e) => { - log::debug!("------------- LOGS ------------------"); + log::error!("------------- LOGS ------------------"); for log in &e.meta.logs { - log::debug!("{log:?}"); + log::error!("{log:?}"); } Err(anyhow::format_err!("Failed to swap {:?}", e.err)) } @@ -561,29 +567,17 @@ fn default_shared_object_dirs() -> Vec { } fn setup_test_chain( - _programs: &Vec, + programs: &Vec, clock: &Clock, dump: &ExecutionDump, - _instruction_program: &Pubkey, + instruction: &Instruction, ) -> anyhow::Result { - // We need to intercept logs to capture program log output - let log_filter = "solana_rbpf=trace,\ - solana_runtime::message_processor=debug,\ - solana_runtime::system_instruction_processor=trace,\ - solana_program_test=info,\ - solana_metrics::metrics=warn,\ - tarpc=error,\ - info"; - let env_logger = - env_logger::Builder::from_env(env_logger::Env::new().default_filter_or(log_filter)) - .format_timestamp_nanos() - .build(); - let _ = log::set_boxed_logger(Box::new(env_logger)); - let mut program_test = LiteSVM::new(); program_test.set_sysvar(clock); + let mut accounts_list = programs.clone(); + accounts_list.extend(instruction.accounts.iter().map(|x| x.pubkey)); - initialize_accounts(&mut program_test, dump)?; + initialize_accounts(&mut program_test, dump, &accounts_list)?; let path = find_file(format!("autobahn_executor.so").as_str()).unwrap(); log::debug!("Adding program: {:?} at {path:?}", autobahn_executor::ID); program_test.add_program_from_file(autobahn_executor::ID, path)?; From 040511ebbf85595d9dc58c6617922e2cbcd054f3 Mon Sep 17 00:00:00 2001 From: godmodegalactus Date: Fri, 25 Oct 2024 16:34:58 +0200 Subject: [PATCH 5/5] adding a todo for token extention program --- programs/simulator/tests/cases/test_swap_from_dump.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/programs/simulator/tests/cases/test_swap_from_dump.rs b/programs/simulator/tests/cases/test_swap_from_dump.rs index 719c19c..d0ecc91 100644 --- a/programs/simulator/tests/cases/test_swap_from_dump.rs +++ b/programs/simulator/tests/cases/test_swap_from_dump.rs @@ -498,6 +498,7 @@ fn set_balance( let mut data = vec![0u8; 165]; if is_2022 { + // TODO: to properly setup extensions, this is not sufficient let account = spl_token_2022::state::Account { mint, owner,