Merge pull request #19 from godmodegalactus/adding_prioritization_fees
adding prioritization fees for market makers
This commit is contained in:
commit
70af47d9fe
|
@ -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",
|
||||
|
|
|
@ -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" }
|
||||
|
|
19
src/cli.rs
19
src/cli.rs
|
@ -1,3 +1,5 @@
|
|||
use solana_clap_utils::input_validators::is_valid_percentage;
|
||||
|
||||
use {
|
||||
clap::{crate_description, crate_name, App, Arg, ArgMatches},
|
||||
solana_clap_utils::input_validators::{is_url, is_url_or_moniker},
|
||||
|
@ -20,6 +22,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 +40,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 +172,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)
|
||||
.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"),
|
||||
)
|
||||
}
|
||||
|
||||
/// Parses a clap `ArgMatches` structure into a `Config`
|
||||
|
@ -243,5 +257,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("Percentage of transactions having prioritization fees"),
|
||||
None => 0,
|
||||
};
|
||||
args
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -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,9 +91,9 @@ fn main() {
|
|||
None
|
||||
};
|
||||
|
||||
let tpu_client_pool = Arc::new(RotatingQueue::<Arc<TpuClient<QuicPool, QuicConnectionManager, QuicConfig>>>::new(
|
||||
number_of_tpu_clients,
|
||||
|| {
|
||||
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(
|
||||
|
@ -102,8 +104,7 @@ fn main() {
|
|||
)
|
||||
.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();
|
||||
|
|
|
@ -10,17 +10,19 @@ 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},
|
||||
matching::Side,
|
||||
};
|
||||
use rand::{distributions::Uniform, prelude::Distribution};
|
||||
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 +36,7 @@ pub fn create_ask_bid_transaction(
|
|||
c: &PerpMarketCache,
|
||||
mango_account_pk: Pubkey,
|
||||
mango_account_signer: &Keypair,
|
||||
prioritization_fee: u64,
|
||||
) -> Transaction {
|
||||
let mango_account_signer_pk = to_sp_pk(&mango_account_signer.pubkey());
|
||||
let offset = rand::random::<i8>() as i64;
|
||||
|
@ -42,6 +45,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_fee > 0 {
|
||||
let pfees = compute_budget::ComputeBudgetInstruction::set_compute_unit_price(
|
||||
prioritization_fee,
|
||||
);
|
||||
instructions.push(pfees);
|
||||
}
|
||||
|
||||
let cancel_ix: Instruction = to_sdk_instruction(
|
||||
cancel_all_perp_orders(
|
||||
&c.mango_program_pk,
|
||||
|
@ -55,6 +66,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 +94,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,28 +122,58 @@ 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()),
|
||||
))
|
||||
}
|
||||
|
||||
fn generate_random_fees(prioritization_fee_proba : u8, n: usize, min_fee: u64, max_fee: u64) -> Vec<u64> {
|
||||
let mut rng = rand::thread_rng();
|
||||
let range = Uniform::from(min_fee..max_fee);
|
||||
let range_probability = Uniform::from(1..100);
|
||||
(0..n)
|
||||
.map(|_| {
|
||||
if prioritization_fee_proba == 0 {
|
||||
0
|
||||
} else {
|
||||
if range_probability.sample(&mut rng) <= prioritization_fee_proba {
|
||||
range.sample(&mut rng) as u64
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
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_fee_proba: 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_by_market = generate_random_fees(prioritization_fee_proba, perp_market_caches.len(), 100, 1000);
|
||||
for (i,c) in perp_market_caches.iter().enumerate() {
|
||||
let prioritization_fee = prioritization_fee_by_market[i];
|
||||
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 +186,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,
|
||||
});
|
||||
if sent.is_err() {
|
||||
println!(
|
||||
|
@ -159,11 +203,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_fee_proba: u8,
|
||||
) {
|
||||
let mut transactions = Vec::<_>::with_capacity(txs_batch_size);
|
||||
|
||||
|
@ -171,22 +218,29 @@ pub fn send_mm_transactions_batched(
|
|||
// update quotes 2x per second
|
||||
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(
|
||||
let prioritization_fee_for_tx = generate_random_fees(prioritization_fee_proba, txs_batch_size, 100, 1000);
|
||||
for i in 0..txs_batch_size {
|
||||
let prioritization_fee = prioritization_fee_for_tx[i];
|
||||
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 +249,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 +275,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_fee_proba: u8,
|
||||
) -> Vec<JoinHandle<()>> {
|
||||
account_keys_parsed
|
||||
.iter()
|
||||
|
@ -247,7 +305,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 +312,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 +325,7 @@ pub fn start_market_making_threads(
|
|||
&mango_account_signer,
|
||||
blockhash.clone(),
|
||||
current_slot.as_ref(),
|
||||
prioritization_fee_proba,
|
||||
);
|
||||
} else {
|
||||
send_mm_transactions(
|
||||
|
@ -278,6 +337,7 @@ pub fn start_market_making_threads(
|
|||
&mango_account_signer,
|
||||
blockhash.clone(),
|
||||
current_slot.as_ref(),
|
||||
prioritization_fee_proba,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
Loading…
Reference in New Issue