From 31cbd96897fc1bdab51f564422cf7a2aebfe7e1d Mon Sep 17 00:00:00 2001 From: Godmode Galactus Date: Tue, 21 Feb 2023 09:49:20 +0100 Subject: [PATCH] adding identity, adding bootcode for keeper --- Cargo.toml | 2 + deps/mango-v3 | 1 - deps/solana | 1 - src/cli.rs | 25 +++++++- src/confirmation_strategies.rs | 8 +-- src/helpers.rs | 9 +++ src/keeper.rs | 104 +++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/main.rs | 43 ++++++-------- src/market_markers.rs | 19 ++---- src/states.rs | 2 + 11 files changed, 169 insertions(+), 46 deletions(-) delete mode 160000 deps/mango-v3 delete mode 160000 deps/solana create mode 100644 src/keeper.rs diff --git a/Cargo.toml b/Cargo.toml index 589fd5b..a39cb23 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,8 @@ license = "Apache-2.0" homepage = "https://solana.com/" publish = false +rust-version = "1.66.1" + [dependencies] borsh = "0.9.3" chrono = "0.4.19" diff --git a/deps/mango-v3 b/deps/mango-v3 deleted file mode 160000 index 771cabe..0000000 --- a/deps/mango-v3 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 771cabea1cb848439d282e43bf5f0e20ef7c9703 diff --git a/deps/solana b/deps/solana deleted file mode 160000 index 030eb5f..0000000 --- a/deps/solana +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 030eb5f2caadebeb5d656c1a0b2d2058ea4bd242 diff --git a/src/cli.rs b/src/cli.rs index af66fb8..0840cd0 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -23,6 +23,7 @@ pub struct Config { pub mango_cluster: String, pub txs_batch_size: Option, pub priority_fees_proba: u8, + pub authority: Keypair, } impl Default for Config { @@ -41,6 +42,7 @@ impl Default for Config { mango_cluster: "testnet.0".to_string(), txs_batch_size: None, priority_fees_proba: 0, + authority: Keypair::new(), } } } @@ -180,7 +182,18 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> { .validator(is_valid_percentage) .takes_value(true) .required(false) - .help("Takes percentage of transaction we want to add random prioritization fees to, prioritization fees are random number between 100-1000"), + .help("Takes percentage of transaction we want to add random prioritization fees to, prioritization fees are random number between 100-1000") + ) + .arg( + Arg::with_name("keeper-authority") + .long("keeper-authority") + .short("ka") + .value_name("STR") + .takes_value(true) + .required(false) + .help( + "If specified, authority keypair would be used to pay for keeper transactions", + ), ) } @@ -262,5 +275,15 @@ pub fn extract_args(matches: &ArgMatches) -> Config { Some(x) => x.parse().expect("Percentage of transactions having prioritization fees"), None => 0, }; + let (_, kp_auth_path) = ConfigInput::compute_keypair_path_setting( + matches.value_of("keeper-authority").unwrap_or(""), + &config.keypair_path, + ); + + if let Ok(kpa) = read_keypair_file(kp_auth_path) { + args.authority = kpa; + } else if matches.is_present("identity") { + panic!("could not parse identity path"); + } args } diff --git a/src/confirmation_strategies.rs b/src/confirmation_strategies.rs index ac35a68..cd77896 100644 --- a/src/confirmation_strategies.rs +++ b/src/confirmation_strategies.rs @@ -23,7 +23,6 @@ use solana_transaction_status::RewardType; use crate::{ helpers::seconds_since, - rotating_queue::RotatingQueue, states::{BlockData, TransactionConfirmRecord, TransactionSendRecord}, }; @@ -201,7 +200,7 @@ pub fn confirmation_by_querying_rpc( } pub fn confirmations_by_blocks( - clients: RotatingQueue>, + client: Arc, current_slot: &AtomicU64, recv_limit: usize, tx_record_rx: Receiver, @@ -245,8 +244,7 @@ pub fn confirmations_by_blocks( let commitment_confirmation = CommitmentConfig { commitment: CommitmentLevel::Confirmed, }; - let block_res = clients - .get() + let block_res = client .get_blocks_with_commitment(last_slot, None, commitment_confirmation) .unwrap(); @@ -264,7 +262,7 @@ pub fn confirmations_by_blocks( .map(|x| x.to_vec()) { let map = transaction_map.clone(); - let client = clients.get().clone(); + let client = client.clone(); let tx_confirm_records = tx_confirm_records.clone(); let tx_block_data = tx_block_data.clone(); let joinble = Builder::new() diff --git a/src/helpers.rs b/src/helpers.rs index 5163764..869cd52 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -245,6 +245,13 @@ pub fn get_mango_market_perps_cache( .div(I80F48::from_num(perp_market.base_lot_size)) .to_num(); + let root_bank = &mango_group_config.tokens[market_index].root_key; + let root_bank = Pubkey::from_str(root_bank.as_str()).unwrap(); + let node_banks = mango_group_config.tokens[market_index] + .node_keys + .iter() + .map(|x| Pubkey::from_str(x.as_str()).unwrap()) + .collect(); PerpMarketCache { order_base_lots, price, @@ -254,6 +261,8 @@ pub fn get_mango_market_perps_cache( mango_cache_pk, perp_market_pk, perp_market, + root_bank, + node_banks, } }) .collect() diff --git a/src/keeper.rs b/src/keeper.rs new file mode 100644 index 0000000..4746bea --- /dev/null +++ b/src/keeper.rs @@ -0,0 +1,104 @@ +use std::{ + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, RwLock, + }, + thread::{Builder, JoinHandle}, +}; + +use solana_client::tpu_client::TpuClient; +use solana_quic_client::{QuicConfig, QuicConnectionManager, QuicPool}; +use solana_sdk::{ + compute_budget::ComputeBudgetInstruction, hash::Hash, instruction::Instruction, + message::Message, signature::Keypair, signer::Signer, transaction::Transaction, +}; + +use crate::{helpers::to_sdk_instruction, states::PerpMarketCache}; + +fn create_root_bank_update_instructions(perp_markets: &Vec) -> Vec { + perp_markets + .iter() + .map(|perp_market| { + let ix = mango::instruction::update_root_bank( + &perp_market.mango_program_pk, + &perp_market.mango_group_pk, + &perp_market.mango_cache_pk, + &perp_market.root_bank, + perp_market.node_banks.as_slice(), + ) + .unwrap(); + to_sdk_instruction(ix) + }) + .collect() +} + +fn create_update_price_cache_instructions(perp_markets: &Vec) -> Vec { + perp_markets + .iter() + .map(|perp_market| { + let ix = mango::instruction::cache_prices( + &perp_market.mango_program_pk, + &perp_market.mango_group_pk, + &perp_market.mango_cache_pk, + perp_market.node_banks.as_slice(), + ) + .unwrap(); + to_sdk_instruction(ix) + }) + .collect() +} + +pub fn send_transaction( + tpu_client: Arc>, + ixs: &[Instruction], + blockhash: Arc>, + payer: &Keypair, +) { + let mut tx = Transaction::new_unsigned(Message::new(ixs, Some(&payer.pubkey()))); + if let Ok(recent_blockhash) = blockhash.read() { + tx.sign(&[payer], *recent_blockhash); + } + tpu_client.send_transaction(&tx); +} + +pub fn start_root_bank_keeper( + exit_signal: Arc, + tpu_client: Arc>, + perp_markets: Vec, + blockhash: Arc>, + authority: &Keypair, +) -> JoinHandle<()> { + let authority = Keypair::from_bytes(&authority.to_bytes()).unwrap(); + Builder::new() + .name("updating root bank keeper".to_string()) + .spawn(move || { + let tpu_client = tpu_client.clone(); + let mut root_update_ixs = create_root_bank_update_instructions(&perp_markets); + let mut cache_price = create_update_price_cache_instructions(&perp_markets); + + let blockhash = blockhash.clone(); + + // add prioritization instruction + let prioritization_ix = ComputeBudgetInstruction::set_compute_unit_price(100); + root_update_ixs.insert(0, prioritization_ix.clone()); + cache_price.insert(0, prioritization_ix); + loop { + if exit_signal.load(Ordering::Relaxed) { + break; + } + send_transaction( + tpu_client.clone(), + root_update_ixs.as_slice(), + blockhash.clone(), + &authority, + ); + send_transaction( + tpu_client.clone(), + cache_price.as_slice(), + blockhash.clone(), + &authority, + ); + } + }) + .unwrap() +} diff --git a/src/lib.rs b/src/lib.rs index bc83105..d370761 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ pub mod cli; pub mod confirmation_strategies; pub mod helpers; +pub mod keeper; pub mod mango; pub mod market_markers; pub mod rotating_queue; diff --git a/src/main.rs b/src/main.rs index a6c22e6..13f54db 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,13 +9,11 @@ use solana_bench_mango::{ }, mango::{AccountKeys, MangoConfig}, market_markers::start_market_making_threads, - rotating_queue::RotatingQueue, states::{BlockData, PerpMarketCache, TransactionConfirmRecord, TransactionSendRecord}, }; use solana_client::{ connection_cache::ConnectionCache, rpc_client::RpcClient, tpu_client::TpuClient, }; -use solana_quic_client::{QuicConfig, QuicConnectionManager, QuicPool}; use solana_sdk::commitment_config::CommitmentConfig; use std::{ @@ -54,7 +52,10 @@ fn main() { let transaction_save_file = transaction_save_file.clone(); let block_data_save_file = block_data_save_file.clone(); - info!("Connecting to the cluster"); + info!( + "Connecting to the cluster {}, {}", + json_rpc_url, websocket_url + ); let account_keys_json = fs::read_to_string(account_keys).expect("unable to read accounts file"); let account_keys_parsed: Vec = @@ -71,13 +72,10 @@ fn main() { .find(|g| g.name == *mango_group_id) .unwrap(); - let number_of_tpu_clients: usize = 1; - let rpc_clients = RotatingQueue::>::new(number_of_tpu_clients, || { - Arc::new(RpcClient::new_with_commitment( - json_rpc_url.to_string(), - CommitmentConfig::confirmed(), - )) - }); + let rpc_client = Arc::new(RpcClient::new_with_commitment( + json_rpc_url.to_string(), + CommitmentConfig::confirmed(), + )); let connection_cache = ConnectionCache::new_with_client_options( 4, @@ -91,20 +89,15 @@ fn main() { None }; - let tpu_client_pool = Arc::new(RotatingQueue::< - Arc>, - >::new(number_of_tpu_clients, || { - let quic_connection_cache = quic_connection_cache.clone(); - Arc::new( - TpuClient::new_with_connection_cache( - rpc_clients.get().clone(), - &websocket_url, - solana_client::tpu_client::TpuClientConfig::default(), - quic_connection_cache.unwrap(), - ) - .unwrap(), + let tpu_client = Arc::new( + TpuClient::new_with_connection_cache( + rpc_client.clone(), + &websocket_url, + solana_client::tpu_client::TpuClientConfig::default(), + quic_connection_cache.unwrap(), ) - })); + .unwrap(), + ); info!( "accounts:{:?} markets:{:?} quotes_per_second:{:?} expected_tps:{:?} duration:{:?}", @@ -144,7 +137,7 @@ fn main() { exit_signal.clone(), blockhash.clone(), current_slot.clone(), - tpu_client_pool.clone(), + tpu_client.clone(), &duration, *quotes_per_second, *txs_batch_size, @@ -170,7 +163,7 @@ fn main() { //confirmation_by_querying_rpc(recv_limit, rpc_client.clone(), &tx_record_rx, tx_confirm_records.clone(), tx_timeout_records.clone()); confirmations_by_blocks( - rpc_clients, + rpc_client.clone(), ¤t_slot, recv_limit, tx_record_rx, diff --git a/src/market_markers.rs b/src/market_markers.rs index e5569c8..1094a17 100644 --- a/src/market_markers.rs +++ b/src/market_markers.rs @@ -28,7 +28,6 @@ use solana_sdk::{ use crate::{ helpers::{to_sdk_instruction, to_sp_pk}, mango::AccountKeys, - rotating_queue::RotatingQueue, states::{PerpMarketCache, TransactionSendRecord}, }; @@ -153,9 +152,7 @@ pub fn send_mm_transactions( quotes_per_second: u64, perp_market_caches: &Vec, tx_record_sx: &Sender, - tpu_client_pool: Arc< - RotatingQueue>>, - >, + tpu_client: Arc>, mango_account_pk: Pubkey, mango_account_signer: &Keypair, blockhash: Arc>, @@ -178,7 +175,7 @@ pub fn send_mm_transactions( if let Ok(recent_blockhash) = blockhash.read() { tx.sign(&[mango_account_signer], *recent_blockhash); } - let tpu_client = tpu_client_pool.get(); + let tpu_client = tpu_client.clone(); tpu_client.send_transaction(&tx); let sent = tx_record_sx.send(TransactionSendRecord { signature: tx.signatures[0], @@ -203,9 +200,7 @@ pub fn send_mm_transactions_batched( quotes_per_second: u64, perp_market_caches: &Vec, tx_record_sx: &Sender, - tpu_client_pool: Arc< - RotatingQueue>>, - >, + tpu_client: Arc>, mango_account_pk: Pubkey, mango_account_signer: &Keypair, blockhash: Arc>, @@ -236,7 +231,7 @@ pub fn send_mm_transactions_batched( tx.0.sign(&[mango_account_signer], *recent_blockhash); } } - let tpu_client = tpu_client_pool.get(); + let tpu_client = tpu_client.clone(); if tpu_client .try_send_transaction_batch( &transactions.iter().map(|x| x.0.clone()).collect_vec().as_slice(), @@ -275,9 +270,7 @@ pub fn start_market_making_threads( exit_signal: Arc, blockhash: Arc>, current_slot: Arc, - tpu_client_pool: Arc< - RotatingQueue>>, - >, + tpu_client: Arc>, duration: &Duration, quotes_per_second: u64, txs_batch_size: Option, @@ -288,7 +281,7 @@ pub fn start_market_making_threads( .map(|account_keys| { let _exit_signal = exit_signal.clone(); // having a tpu client for each MM - let tpu_client_pool = tpu_client_pool.clone(); + let tpu_client_pool = tpu_client.clone(); let blockhash = blockhash.clone(); let current_slot = current_slot.clone(); diff --git a/src/states.rs b/src/states.rs index 10478a8..928ba97 100644 --- a/src/states.rs +++ b/src/states.rs @@ -43,6 +43,8 @@ pub struct PerpMarketCache { pub mango_cache_pk: Pubkey, pub perp_market_pk: Pubkey, pub perp_market: PerpMarket, + pub root_bank: Pubkey, + pub node_banks: Vec, } pub struct _TransactionInfo {