diff --git a/Cargo.lock b/Cargo.lock index 0a57a45..b0cd8db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5955,6 +5955,7 @@ dependencies = [ "serde_derive", "serde_json", "serde_with 2.3.3", + "sha2 0.10.8", "solana-account-decoder", "solana-client", "solana-sdk", @@ -6758,11 +6759,13 @@ version = "0.1.0" dependencies = [ "anyhow", "autobahn-executor", + "base64 0.12.3", "bincode", "bonfida-test-utils", "env_logger", "log 0.4.21", "router-test-lib", + "sha2 0.10.8", "solana-address-lookup-table-program", "solana-program", "solana-program-test", diff --git a/lib/dex-infinity/src/infinity.rs b/lib/dex-infinity/src/infinity.rs index fdc6ce6..2917876 100644 --- a/lib/dex-infinity/src/infinity.rs +++ b/lib/dex-infinity/src/infinity.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::collections::HashSet; +use std::str::FromStr; use std::sync::Arc; use jupiter_amm_interface::{Amm, QuoteParams, SwapMode}; @@ -106,6 +107,7 @@ impl DexInterface for InfinityDex { fn program_ids(&self) -> HashSet { [ + Pubkey::from_str("5ocnV1qiCgaQR8Jb8xWnVbApfaygJ8tNoZfgPwsgx9kx").unwrap(), s_controller_lib::program::ID, sanctum_spl_multi_stake_pool_program::ID, sanctum_spl_stake_pool_program::ID, diff --git a/lib/router-lib/Cargo.toml b/lib/router-lib/Cargo.toml index 3e1f870..15a41b3 100644 --- a/lib/router-lib/Cargo.toml +++ b/lib/router-lib/Cargo.toml @@ -32,3 +32,4 @@ lz4 = "1.25.0" async-channel = "1.9.0" lazy_static = "1.5.0" anchor-spl = { version = "0.29.0", features = ["associated_token"] } +sha2 = "0.10.8" 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 806622d..8ee3baf 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 @@ -8,15 +8,19 @@ use itertools::Itertools; use mango_feeds_connector::chain_data::AccountData; use router_feed_lib::router_rpc_client::{RouterRpcClient, RouterRpcClientTrait}; use router_test_lib::{execution_dump, serialize}; +use serde::Deserialize; +use sha2::{Digest, Sha256}; use solana_sdk::account::ReadableAccount; use solana_sdk::clock::Clock; +use solana_sdk::config::program; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::Keypair; use solana_sdk::signer::Signer; use solana_sdk::sysvar::SysvarId; -use std::collections::HashSet; +use solana_sdk::bpf_loader_upgradeable::UpgradeableLoaderState; use std::sync::Arc; use tracing::{debug, error}; +use std::str::FromStr; pub async fn run_dump_mainnet_data( dex: Arc, @@ -67,7 +71,7 @@ pub async fn run_dump_mainnet_data_with_custom_amount( let mut skipped = 0; let mut success = 0; - let mut accounts_needed = HashSet::new(); + let mut accounts_needed = dex.program_ids(); for id in edges_identifiers { accounts_needed.insert(id.input_mint()); accounts_needed.insert(id.output_mint()); @@ -123,7 +127,17 @@ pub async fn run_dump_mainnet_data_with_custom_amount( for x in accounts_needed.iter().take(10) { println!("- {} ", x); } - rpc_client.get_multiple_accounts(&accounts_needed).await?; + let accounts = rpc_client.get_multiple_accounts(&accounts_needed).await?; + + for (_, account) in accounts { + // get buffer for upgradable programs + if account.owner == solana_sdk::bpf_loader_upgradeable::ID { + let state = bincode::deserialize::(&account.data).unwrap(); + if let UpgradeableLoaderState::Program { programdata_address } = state { + rpc_client.get_account(&programdata_address).await?; + } + } + } println!("Error count: {}", errors); println!("Skipped count: {}", skipped); @@ -312,6 +326,31 @@ pub async fn run_dump_swap_ix_with_custom_amount( println!("Success count: {}", success); println!("Exactout Success count: {}", exact_out_sucess); + for program in dump.programs.clone() { + let program_account = account_provider.account(&program)?; + + dump.accounts.insert(program, program_account.account.clone()); + // use downloaded buffers for the upgradable programs + if *program_account.account.owner() == solana_sdk::bpf_loader_upgradeable::ID { + let state = bincode::deserialize::(program_account.account.data()).unwrap(); + if let UpgradeableLoaderState::Program { programdata_address } = state { + let program_data_account = account_provider.account(&programdata_address)?; + dump.accounts.insert(programdata_address, program_data_account.account); + } + } + } + + for program in &dump.programs { + debug!("program : {program:?}"); + } + + for (pk, program) in &dump.accounts { + let mut hasher = Sha256::new(); + hasher.update(program.data()); + let result = hasher.finalize(); + let base64 = base64::encode(result); + debug!("account : {pk:?} dump : {base64:?}"); + } serialize::serialize_to_file( &dump, &format!("../../programs/simulator/tests/fixtures/{}", dump_name).to_string(), diff --git a/lib/router-test-lib/src/execution_dump.rs b/lib/router-test-lib/src/execution_dump.rs index 78d0fc7..1632dc8 100644 --- a/lib/router-test-lib/src/execution_dump.rs +++ b/lib/router-test-lib/src/execution_dump.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, HashSet}; use serde_derive::{Deserialize, Serialize}; use solana_sdk::account::AccountSharedData; @@ -17,7 +17,7 @@ pub struct ExecutionItem { #[derive(Clone, Serialize, Deserialize)] pub struct ExecutionDump { pub wallet_keypair: String, - pub programs: Vec, + pub programs: HashSet, pub cache: Vec, pub accounts: HashMap, } diff --git a/programs/simulator/tests/cases/test_swap_from_dump.rs b/programs/simulator/tests/cases/test_swap_from_dump.rs index 5c3bfa2..e8b1d1a 100644 --- a/programs/simulator/tests/cases/test_swap_from_dump.rs +++ b/programs/simulator/tests/cases/test_swap_from_dump.rs @@ -23,6 +23,8 @@ use spl_token_2022::state::AccountState as AccountState2022; use std::collections::HashMap; use std::process::exit; use std::str::FromStr; +// use sha2::Sha256; +// use sha2::Digest; struct TestLogSyscallStubs; impl SyscallStubs for TestLogSyscallStubs { @@ -121,16 +123,18 @@ async fn run_all_swap_from_dump(dump_name: &str) -> Result, Er continue; } - let mut ctx = setup_test_chain(&data.programs, &clock).await; + let instruction = deserialize_instruction("e.instruction)?; + + let programs = data.programs.iter().copied().collect(); + let mut ctx = setup_test_chain(&programs, &clock, &data).await; create_wallet(&mut ctx, wallet.pubkey()); let initial_in_balance = quote.input_amount * 2; let initial_out_balance = 1_000_000; - let instruction = deserialize_instruction("e.instruction)?; - - initialize_instruction_accounts(&mut ctx, &data, &instruction).await?; + // let slot = ctx.banks_client.get_root_slot().await.unwrap(); + // ctx.warp_to_slot(slot+3).unwrap(); let input_mint_is_2022 = is_2022(&data.accounts, quote.input_mint).await; let output_mint_is_2022 = is_2022(&data.accounts, quote.output_mint).await; @@ -152,6 +156,20 @@ 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 { + 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()); + } + + if let Some(cus) = simulate_cu_usage(&mut ctx, &wallet, &instruction).await { cus_required.push(cus); } @@ -324,31 +342,21 @@ fn deserialize_instruction(swap_ix: &Vec) -> anyhow::Result { Ok(instruction) } -async fn initialize_instruction_accounts( - ctx: &mut ProgramTestContext, +async fn initialize_accounts( + program_test: &mut ProgramTest, dump: &ExecutionDump, - instruction: &Instruction, ) -> anyhow::Result<()> { - for account_meta in &instruction.accounts { - if dump.programs.contains(&account_meta.pubkey) { - continue; - } - if let Some(account) = dump.accounts.get(&account_meta.pubkey) { - if account.executable() { - continue; - } - debug!("Setting data for {}", account_meta.pubkey); - ctx.set_account(&account_meta.pubkey, account); - } else { - if ctx - .banks_client - .get_account(account_meta.pubkey) - .await? - .is_none() - { - debug!("Missing data for {}", account_meta.pubkey); // Can happen for empty oracle account... - } - } + + println!("initializing accounts : {:?}", dump.accounts.len() ); + for (pk, account) in &dump.accounts { + println!("Setting data for {}", pk); + program_test.add_account(*pk, solana_sdk::account::Account { + lamports: account.lamports(), + owner: *account.owner(), + data: account.data().to_vec(), + rent_epoch: account.rent_epoch(), + executable: account.executable(), + }); } Ok(()) @@ -518,7 +526,9 @@ fn create_wallet(ctx: &mut ProgramTestContext, address: Pubkey) { ); } -async fn setup_test_chain(programs: &Vec, clock: &Clock) -> ProgramTestContext { +async fn setup_test_chain(programs: &Vec, clock: &Clock, + dump: &ExecutionDump, +) -> ProgramTestContext { // We need to intercept logs to capture program log output let log_filter = "solana_rbpf=trace,\ solana_runtime::message_processor=debug,\ @@ -534,20 +544,26 @@ async fn setup_test_chain(programs: &Vec, clock: &Clock) -> ProgramTestC let _ = log::set_boxed_logger(Box::new(env_logger)); let mut program_test = ProgramTest::default(); + + initialize_accounts(&mut program_test, dump).await.unwrap(); + + 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); - + // TODO: make this dynamic based on routes program_test.set_compute_max_units(1_400_000); - let program_test_context = program_test.start_with_context().await; + 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(); + program_test_context } diff --git a/programs/simulator/tests/fixtures/675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8.so b/programs/simulator/tests/fixtures/675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8.so index e9428e1..2799004 100644 Binary files a/programs/simulator/tests/fixtures/675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8.so and b/programs/simulator/tests/fixtures/675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8.so differ diff --git a/programs/simulator/tests/fixtures/CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C.so b/programs/simulator/tests/fixtures/CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C.so index 741dd30..8e28bda 100644 Binary files a/programs/simulator/tests/fixtures/CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C.so and b/programs/simulator/tests/fixtures/CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C.so differ diff --git a/programs/simulator/tests/fixtures/download-programs.sh b/programs/simulator/tests/fixtures/download-programs.sh new file mode 100644 index 0000000..9ec22e0 --- /dev/null +++ b/programs/simulator/tests/fixtures/download-programs.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +for filename in programs/simulator/tests/fixtures/*.so; do + filename=$(basename $filename) + filename="${filename%.*}" + echo $filename + solana program dump -um $filename $SOURCE/$filename.so +done \ No newline at end of file diff --git a/programs/simulator/tests/fixtures/whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc.so b/programs/simulator/tests/fixtures/whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc.so index 08255fa..d6cd982 100644 Binary files a/programs/simulator/tests/fixtures/whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc.so and b/programs/simulator/tests/fixtures/whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc.so differ