adding prioritization fees for market makers

This commit is contained in:
Godmode Galactus 2023-02-21 11:04:02 +01:00
parent 9e13cfcc93
commit 37cfc81c83
No known key found for this signature in database
GPG Key ID: A04142C71ABB0DEA
8 changed files with 124 additions and 33 deletions

10
Cargo.lock generated
View File

@ -2453,6 +2453,15 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146"
[[package]]
name = "iter_tools"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "531cafdc99b3b3252bb32f5620e61d56b19415efc19900b12d1b2e7483854897"
dependencies = [
"itertools 0.10.5",
]
[[package]]
name = "itertools"
version = "0.9.0"
@ -4899,6 +4908,7 @@ dependencies = [
"csv",
"fixed",
"fixed-macro",
"iter_tools",
"log",
"mango",
"mango-common",

View File

@ -23,6 +23,7 @@ serde = "1.0.136"
serde_derive = "1.0.103"
serde_json = "1.0.79"
serde_yaml = "0.8.23"
iter_tools = "0.1.4"
mango = { git = "https://github.com/blockworks-foundation/mango-v3.git", branch = "mango_bencher_compatible", default-features = false, features = ["no-entrypoint"] }
mango-common = { git = "https://github.com/blockworks-foundation/mango-v3.git", branch = "mango_bencher_compatible" }

View File

@ -20,6 +20,7 @@ pub struct Config {
pub block_data_save_file: String,
pub mango_cluster: String,
pub txs_batch_size: Option<usize>,
pub priority_fees_proba: u8,
}
impl Default for Config {
@ -37,6 +38,7 @@ impl Default for Config {
block_data_save_file: String::new(),
mango_cluster: "testnet.0".to_string(),
txs_batch_size: None,
priority_fees_proba: 0,
}
}
}
@ -168,6 +170,16 @@ pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
.required(false)
.help("If specified, transactions are send in batches of specified size"),
)
.arg(
Arg::with_name("prioritization-fees")
.long("prioritization-fees")
.value_name("UINT")
.min_values(1)
.max_values(100)
.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"),
)
}
/// Parses a clap `ArgMatches` structure into a `Config`
@ -243,5 +255,10 @@ pub fn extract_args(matches: &ArgMatches) -> Config {
args.txs_batch_size = matches
.value_of("batch-size")
.map(|batch_size_str| batch_size_str.parse().expect("can't parse batch-size"));
args.priority_fees_proba = match matches.value_of("prioritization-fees") {
Some(x) => x.parse().expect("Prioritization fees is between 1-100"),
None => 0,
};
args
}

View File

@ -64,6 +64,7 @@ pub fn process_signature_confirmation_batch(
market_maker: tx_record.market_maker.to_string(),
slot_processed: tx_record.sent_slot,
timed_out: false,
priority_fees: tx_record.priority_fees,
});
debug!(
@ -371,6 +372,7 @@ pub fn confirmations_by_blocks(
slot_processed: slot,
slot_leader: slot_leader.clone(),
timed_out: false,
priority_fees: transaction_record.priority_fees,
})
}

View File

@ -161,6 +161,7 @@ pub fn write_transaction_data_into_csv(
slot_processed: 0,
successful: false,
timed_out: true,
priority_fees: timeout_record.priority_fees,
})
.unwrap();
}

View File

@ -13,18 +13,19 @@ use solana_bench_mango::{
states::{BlockData, PerpMarketCache, TransactionConfirmRecord, TransactionSendRecord},
};
use solana_client::{
rpc_client::RpcClient, tpu_client::TpuClient, connection_cache::ConnectionCache,
connection_cache::ConnectionCache, rpc_client::RpcClient, tpu_client::TpuClient,
};
use solana_quic_client::{QuicPool, QuicConnectionManager, QuicConfig};
use solana_quic_client::{QuicConfig, QuicConnectionManager, QuicPool};
use solana_sdk::commitment_config::CommitmentConfig;
use std::{
fs,
net::{IpAddr, Ipv4Addr},
sync::{
atomic::{AtomicBool, AtomicU64, Ordering},
Arc, RwLock,
},
thread::{Builder, JoinHandle}, net::{IpAddr, Ipv4Addr},
thread::{Builder, JoinHandle},
};
fn main() {
@ -46,6 +47,7 @@ fn main() {
block_data_save_file,
mango_cluster,
txs_batch_size,
priority_fees_proba,
..
} = &cli_config;
@ -89,21 +91,20 @@ fn main() {
None
};
let tpu_client_pool = Arc::new(RotatingQueue::<Arc<TpuClient<QuicPool, QuicConnectionManager, QuicConfig>>>::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_pool = Arc::new(RotatingQueue::<
Arc<TpuClient<QuicPool, QuicConnectionManager, QuicConfig>>,
>::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(),
)
}));
info!(
"accounts:{:?} markets:{:?} quotes_per_second:{:?} expected_tps:{:?} duration:{:?}",
@ -147,6 +148,7 @@ fn main() {
&duration,
*quotes_per_second,
*txs_batch_size,
*priority_fees_proba,
);
let duration = duration.clone();
let quotes_per_second = quotes_per_second.clone();

View File

@ -10,6 +10,7 @@ use std::{
use chrono::Utc;
use crossbeam_channel::Sender;
use iter_tools::Itertools;
use log::{debug, error, info, warn};
use mango::{
instruction::{cancel_all_perp_orders, place_perp_order2},
@ -17,10 +18,10 @@ use mango::{
};
use solana_client::tpu_client::TpuClient;
use solana_program::pubkey::Pubkey;
use solana_quic_client::{QuicPool, QuicConnectionManager, QuicConfig};
use solana_quic_client::{QuicConfig, QuicConnectionManager, QuicPool};
use solana_sdk::{
hash::Hash, instruction::Instruction, message::Message, signature::Keypair, signer::Signer,
transaction::Transaction,
compute_budget, hash::Hash, instruction::Instruction, message::Message, signature::Keypair,
signer::Signer, transaction::Transaction,
};
use crate::{
@ -34,6 +35,7 @@ pub fn create_ask_bid_transaction(
c: &PerpMarketCache,
mango_account_pk: Pubkey,
mango_account_signer: &Keypair,
prioritization_fees: u32,
) -> Transaction {
let mango_account_signer_pk = to_sp_pk(&mango_account_signer.pubkey());
let offset = rand::random::<i8>() as i64;
@ -42,6 +44,14 @@ pub fn create_ask_bid_transaction(
"price:{:?} price_quote_lots:{:?} order_base_lots:{:?} offset:{:?} spread:{:?}",
c.price, c.price_quote_lots, c.order_base_lots, offset, spread
);
let mut instructions = vec![];
if prioritization_fees > 0 {
let pfees = compute_budget::ComputeBudgetInstruction::set_compute_unit_price(
prioritization_fees as u64,
);
instructions.push(pfees);
}
let cancel_ix: Instruction = to_sdk_instruction(
cancel_all_perp_orders(
&c.mango_program_pk,
@ -55,6 +65,7 @@ pub fn create_ask_bid_transaction(
)
.unwrap(),
);
instructions.push(cancel_ix);
let place_bid_ix: Instruction = to_sdk_instruction(
place_perp_order2(
@ -82,6 +93,7 @@ pub fn create_ask_bid_transaction(
)
.unwrap(),
);
instructions.push(place_bid_ix);
let place_ask_ix: Instruction = to_sdk_instruction(
place_perp_order2(
@ -109,9 +121,10 @@ pub fn create_ask_bid_transaction(
)
.unwrap(),
);
instructions.push(place_ask_ix);
Transaction::new_unsigned(Message::new(
&[cancel_ix, place_bid_ix, place_ask_ix],
instructions.as_slice(),
Some(&mango_account_signer.pubkey()),
))
}
@ -120,17 +133,34 @@ pub fn send_mm_transactions(
quotes_per_second: u64,
perp_market_caches: &Vec<PerpMarketCache>,
tx_record_sx: &Sender<TransactionSendRecord>,
tpu_client_pool: Arc<RotatingQueue<Arc<TpuClient<QuicPool, QuicConnectionManager, QuicConfig>>>>,
tpu_client_pool: Arc<
RotatingQueue<Arc<TpuClient<QuicPool, QuicConnectionManager, QuicConfig>>>,
>,
mango_account_pk: Pubkey,
mango_account_signer: &Keypair,
blockhash: Arc<RwLock<Hash>>,
slot: &AtomicU64,
prioritization_fees: u8,
) {
let mango_account_signer_pk = to_sp_pk(&mango_account_signer.pubkey());
// update quotes 2x per second
for _ in 0..quotes_per_second {
for c in perp_market_caches.iter() {
let mut tx = create_ask_bid_transaction(c, mango_account_pk, &mango_account_signer);
let prioritization_fee = if prioritization_fees != 0 {
if rand::random::<u8>() % 99 + 1 <= prioritization_fees {
rand::random::<u32>() % 900 + 100
} else {
0
}
} else {
0
};
let mut tx = create_ask_bid_transaction(
c,
mango_account_pk,
&mango_account_signer,
prioritization_fee,
);
if let Ok(recent_blockhash) = blockhash.read() {
tx.sign(&[mango_account_signer], *recent_blockhash);
@ -143,6 +173,7 @@ pub fn send_mm_transactions(
sent_slot: slot.load(Ordering::Acquire),
market_maker: mango_account_signer_pk,
market: c.perp_market_pk,
priority_fees: prioritization_fee as u64,
});
if sent.is_err() {
println!(
@ -159,11 +190,14 @@ pub fn send_mm_transactions_batched(
quotes_per_second: u64,
perp_market_caches: &Vec<PerpMarketCache>,
tx_record_sx: &Sender<TransactionSendRecord>,
tpu_client_pool: Arc<RotatingQueue<Arc<TpuClient<QuicPool, QuicConnectionManager, QuicConfig>>>>,
tpu_client_pool: Arc<
RotatingQueue<Arc<TpuClient<QuicPool, QuicConnectionManager, QuicConfig>>>,
>,
mango_account_pk: Pubkey,
mango_account_signer: &Keypair,
blockhash: Arc<RwLock<Hash>>,
slot: &AtomicU64,
prioritization_fees: u8,
) {
let mut transactions = Vec::<_>::with_capacity(txs_batch_size);
@ -172,21 +206,37 @@ pub fn send_mm_transactions_batched(
for _ in 0..quotes_per_second {
for c in perp_market_caches.iter() {
for _ in 0..txs_batch_size {
transactions.push(create_ask_bid_transaction(
c,
mango_account_pk,
&mango_account_signer,
let prioritization_fee = if prioritization_fees != 0 {
if rand::random::<u8>() % 99 + 1 <= prioritization_fees {
rand::random::<u32>() % 900 + 100
} else {
0
}
} else {
0
};
transactions.push((
create_ask_bid_transaction(
c,
mango_account_pk,
&mango_account_signer,
prioritization_fee,
),
prioritization_fee,
));
}
if let Ok(recent_blockhash) = blockhash.read() {
for tx in &mut transactions {
tx.sign(&[mango_account_signer], *recent_blockhash);
tx.0.sign(&[mango_account_signer], *recent_blockhash);
}
}
let tpu_client = tpu_client_pool.get();
if tpu_client
.try_send_transaction_batch(&transactions)
.try_send_transaction_batch(
&transactions.iter().map(|x| x.0.clone()).collect_vec().as_slice(),
)
.is_err()
{
error!("Sending batch failed");
@ -195,11 +245,12 @@ pub fn send_mm_transactions_batched(
for tx in &transactions {
let sent = tx_record_sx.send(TransactionSendRecord {
signature: tx.signatures[0],
signature: tx.0.signatures[0],
sent_at: Utc::now(),
sent_slot: slot.load(Ordering::Acquire),
market_maker: mango_account_signer_pk,
market: c.perp_market_pk,
priority_fees: tx.1 as u64,
});
if sent.is_err() {
error!(
@ -220,10 +271,13 @@ pub fn start_market_making_threads(
exit_signal: Arc<AtomicBool>,
blockhash: Arc<RwLock<Hash>>,
current_slot: Arc<AtomicU64>,
tpu_client_pool: Arc<RotatingQueue<Arc<TpuClient<QuicPool, QuicConnectionManager, QuicConfig>>>>,
tpu_client_pool: Arc<
RotatingQueue<Arc<TpuClient<QuicPool, QuicConnectionManager, QuicConfig>>>,
>,
duration: &Duration,
quotes_per_second: u64,
txs_batch_size: Option<usize>,
prioritization_fees: u8,
) -> Vec<JoinHandle<()>> {
account_keys_parsed
.iter()
@ -247,7 +301,6 @@ pub fn start_market_making_threads(
mango_account_pk
);
//sleep(Duration::from_secs(10));
let tx_record_sx = tx_record_sx.clone();
Builder::new()
@ -255,6 +308,7 @@ pub fn start_market_making_threads(
.spawn(move || {
for _i in 0..duration.as_secs() {
let start = Instant::now();
// send market maker transactions
if let Some(txs_batch_size) = txs_batch_size.clone() {
send_mm_transactions_batched(
@ -267,6 +321,7 @@ pub fn start_market_making_threads(
&mango_account_signer,
blockhash.clone(),
current_slot.as_ref(),
prioritization_fees,
);
} else {
send_mm_transactions(
@ -278,6 +333,7 @@ pub fn start_market_making_threads(
&mango_account_signer,
blockhash.clone(),
current_slot.as_ref(),
prioritization_fees,
);
}

View File

@ -12,6 +12,7 @@ pub struct TransactionSendRecord {
pub sent_slot: Slot,
pub market_maker: Pubkey,
pub market: Pubkey,
pub priority_fees: u64,
}
#[derive(Clone, Serialize)]
@ -29,6 +30,7 @@ pub struct TransactionConfirmRecord {
pub block_hash: String,
pub slot_processed: Slot,
pub timed_out: bool,
pub priority_fees: u64,
}
#[derive(Clone)]