Compare commits
No commits in common. "main" and "v0.1.0" have entirely different histories.
|
@ -1,59 +0,0 @@
|
||||||
name: Rust Build and Clippy Check
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
env:
|
|
||||||
SCCACHE_GHA_ENABLED: true
|
|
||||||
RUSTC_WRAPPER: sccache
|
|
||||||
SCCACHE_CACHE_SIZE: "1G"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_all:
|
|
||||||
name: Rust project
|
|
||||||
runs-on: ubuntu-22.04
|
|
||||||
steps:
|
|
||||||
- name: Install Linux Packages
|
|
||||||
run: |
|
|
||||||
sudo apt-get update -y
|
|
||||||
sudo apt-get install libssl-dev openssl -y
|
|
||||||
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
# The toolchain action should definitely be run before the cache action
|
|
||||||
- uses: actions-rust-lang/setup-rust-toolchain@v1
|
|
||||||
with:
|
|
||||||
# use toolchain version from rust-toolchain.toml
|
|
||||||
components: rustfmt, clippy
|
|
||||||
cache: true
|
|
||||||
# avoid the default "-D warnings" which thrashes cache
|
|
||||||
rustflags: ""
|
|
||||||
|
|
||||||
|
|
||||||
- name: Run sccache-cache
|
|
||||||
uses: mozilla-actions/sccache-action@v0.0.3
|
|
||||||
|
|
||||||
|
|
||||||
# https://github.com/actions/cache/blob/main/examples.md#rust---cargo
|
|
||||||
# https://blog.arriven.wtf/posts/rust-ci-cache/
|
|
||||||
- uses: Swatinem/rust-cache@v2
|
|
||||||
with:
|
|
||||||
# will be covered by sscache
|
|
||||||
cache-targets: false
|
|
||||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
|
||||||
|
|
||||||
|
|
||||||
- name: Early Build
|
|
||||||
run: |
|
|
||||||
cargo build --locked --workspace --tests
|
|
||||||
|
|
||||||
- name: Run fmt+clippy
|
|
||||||
run: |
|
|
||||||
cargo fmt --all --check
|
|
||||||
cargo clippy --locked --workspace --all-targets
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ impl Default for Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defines and builds the CLI args for a run of the benchmark
|
/// Defines and builds the CLI args for a run of the benchmark
|
||||||
pub fn build_args(version: &str) -> App<'_, '_> {
|
pub fn build_args<'a, 'b>(version: &'b str) -> App<'a, 'b> {
|
||||||
App::new(crate_name!())
|
App::new(crate_name!())
|
||||||
.about(crate_description!())
|
.about(crate_description!())
|
||||||
.version(version)
|
.version(version)
|
||||||
|
@ -302,7 +302,7 @@ pub fn extract_args(matches: &ArgMatches) -> Config {
|
||||||
&config.keypair_path,
|
&config.keypair_path,
|
||||||
);
|
);
|
||||||
|
|
||||||
args.keeper_authority = read_keypair_file(kp_auth_path).ok();
|
args.keeper_authority = read_keypair_file(kp_auth_path.clone()).ok();
|
||||||
|
|
||||||
args.number_of_markers_per_mm = match matches.value_of("markets-per-mm") {
|
args.number_of_markers_per_mm = match matches.value_of("markets-per-mm") {
|
||||||
Some(x) => x
|
Some(x) => x
|
||||||
|
|
|
@ -17,8 +17,7 @@ use solana_sdk::{
|
||||||
slot_history::Slot,
|
slot_history::Slot,
|
||||||
};
|
};
|
||||||
use solana_transaction_status::{
|
use solana_transaction_status::{
|
||||||
option_serializer::OptionSerializer, RewardType, TransactionDetails, UiConfirmedBlock,
|
RewardType, TransactionDetails, UiConfirmedBlock, UiTransactionEncoding,
|
||||||
UiTransactionEncoding,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::states::{BlockData, TransactionConfirmRecord, TransactionSendRecord};
|
use crate::states::{BlockData, TransactionConfirmRecord, TransactionSendRecord};
|
||||||
|
@ -33,7 +32,6 @@ pub async fn process_blocks(
|
||||||
tx_block_data: Sender<BlockData>,
|
tx_block_data: Sender<BlockData>,
|
||||||
transaction_map: Arc<DashMap<Signature, (TransactionSendRecord, Instant)>>,
|
transaction_map: Arc<DashMap<Signature, (TransactionSendRecord, Instant)>>,
|
||||||
slot: u64,
|
slot: u64,
|
||||||
commitment: CommitmentLevel,
|
|
||||||
) {
|
) {
|
||||||
let mut mm_transaction_count: u64 = 0;
|
let mut mm_transaction_count: u64 = 0;
|
||||||
let rewards = block.rewards.as_ref().unwrap();
|
let rewards = block.rewards.as_ref().unwrap();
|
||||||
|
@ -47,18 +45,11 @@ pub async fn process_blocks(
|
||||||
|
|
||||||
if let Some(transactions) = &block.transactions {
|
if let Some(transactions) = &block.transactions {
|
||||||
let nb_transactions = transactions.len();
|
let nb_transactions = transactions.len();
|
||||||
let mut mm_cu_consumed: u64 = 0;
|
let mut cu_consumed: u64 = 0;
|
||||||
let mut total_cu_consumed: u64 = 0;
|
|
||||||
for solana_transaction_status::EncodedTransactionWithStatusMeta {
|
for solana_transaction_status::EncodedTransactionWithStatusMeta {
|
||||||
transaction, meta, ..
|
transaction, meta, ..
|
||||||
} in transactions
|
} in transactions
|
||||||
{
|
{
|
||||||
let tx_cu_consumed =
|
|
||||||
meta.as_ref()
|
|
||||||
.map_or(0, |meta| match meta.compute_units_consumed {
|
|
||||||
OptionSerializer::Some(cu_consumed) => cu_consumed,
|
|
||||||
_ => 0,
|
|
||||||
});
|
|
||||||
let transaction = match transaction.decode() {
|
let transaction = match transaction.decode() {
|
||||||
Some(tx) => tx,
|
Some(tx) => tx,
|
||||||
None => {
|
None => {
|
||||||
|
@ -66,11 +57,25 @@ pub async fn process_blocks(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
for signature in &transaction.signatures {
|
for signature in &transaction.signatures {
|
||||||
|
let transaction_record_op = {
|
||||||
|
let rec = transaction_map.get(&signature);
|
||||||
|
match rec {
|
||||||
|
Some(x) => Some(x.clone()),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
};
|
||||||
// add CU in counter
|
// add CU in counter
|
||||||
total_cu_consumed = total_cu_consumed.saturating_add(tx_cu_consumed);
|
if let Some(meta) = &meta {
|
||||||
if let Some((_, (transaction_record, _))) = transaction_map.remove(signature) {
|
match meta.compute_units_consumed {
|
||||||
|
solana_transaction_status::option_serializer::OptionSerializer::Some(x) => {
|
||||||
|
cu_consumed = cu_consumed.saturating_add(x);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(transaction_record) = transaction_record_op {
|
||||||
|
let transaction_record = transaction_record.0;
|
||||||
mm_transaction_count += 1;
|
mm_transaction_count += 1;
|
||||||
mm_cu_consumed = mm_cu_consumed.saturating_add(tx_cu_consumed);
|
|
||||||
|
|
||||||
match tx_confirm_records.send(TransactionConfirmRecord {
|
match tx_confirm_records.send(TransactionConfirmRecord {
|
||||||
signature: transaction_record.signature.to_string(),
|
signature: transaction_record.signature.to_string(),
|
||||||
|
@ -103,6 +108,8 @@ pub async fn process_blocks(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transaction_map.remove(&signature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// push block data
|
// push block data
|
||||||
|
@ -116,11 +123,9 @@ pub async fn process_blocks(
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
},
|
},
|
||||||
number_of_mango_simulation_txs: mm_transaction_count,
|
number_of_mm_transactions: mm_transaction_count,
|
||||||
total_transactions: nb_transactions as u64,
|
total_transactions: nb_transactions as u64,
|
||||||
cu_consumed: total_cu_consumed,
|
cu_consumed: cu_consumed,
|
||||||
cu_consumed_by_mango_simulations: mm_cu_consumed,
|
|
||||||
commitment,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,28 +186,19 @@ pub fn confirmation_by_lite_rpc_notification_stream(
|
||||||
|
|
||||||
match notification {
|
match notification {
|
||||||
NotificationMsg::BlockNotificationMsg(block_notification) => {
|
NotificationMsg::BlockNotificationMsg(block_notification) => {
|
||||||
if block_notification.commitment != CommitmentLevel::Finalized {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let _ = tx_block_data.send(BlockData {
|
let _ = tx_block_data.send(BlockData {
|
||||||
block_hash: block_notification.blockhash.to_string(),
|
block_hash: block_notification.blockhash.to_string(),
|
||||||
block_leader: block_notification.block_leader,
|
block_leader: block_notification.block_leader,
|
||||||
block_slot: block_notification.slot,
|
block_slot: block_notification.slot,
|
||||||
block_time: block_notification.block_time,
|
block_time: block_notification.block_time,
|
||||||
number_of_mango_simulation_txs: block_notification.transaction_found,
|
number_of_mm_transactions: block_notification.transaction_found,
|
||||||
total_transactions: block_notification.total_transactions,
|
total_transactions: block_notification.total_transactions,
|
||||||
cu_consumed: block_notification.total_cu_consumed,
|
cu_consumed: block_notification.cu_consumed_by_txs,
|
||||||
cu_consumed_by_mango_simulations: block_notification.cu_consumed_by_txs,
|
|
||||||
commitment: block_notification.commitment,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
NotificationMsg::UpdateTransactionMsg(tx_update_notifications) => {
|
NotificationMsg::UpdateTransactionMsg(tx_update_notifications) => {
|
||||||
|
|
||||||
for tx_notification in tx_update_notifications {
|
for tx_notification in tx_update_notifications {
|
||||||
if tx_notification.commitment != CommitmentLevel::Finalized {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(value) = transaction_map.get(&tx_notification.signature) {
|
if let Some(value) = transaction_map.get(&tx_notification.signature) {
|
||||||
let (tx_sent_record, _) = value.clone();
|
let (tx_sent_record, _) = value.clone();
|
||||||
let error = match &tx_notification.transaction_status {
|
let error = match &tx_notification.transaction_status {
|
||||||
|
@ -250,9 +246,9 @@ pub fn confirmation_by_lite_rpc_notification_stream(
|
||||||
};
|
};
|
||||||
|
|
||||||
let cleaner_jh = {
|
let cleaner_jh = {
|
||||||
let transaction_map = transaction_map;
|
let transaction_map = transaction_map.clone();
|
||||||
let exit_signal = exit_signal;
|
let exit_signal = exit_signal.clone();
|
||||||
let tx_confirm_records = tx_confirm_records;
|
let tx_confirm_records = tx_confirm_records.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
tokio::time::sleep(Duration::from_secs(60)).await;
|
tokio::time::sleep(Duration::from_secs(60)).await;
|
||||||
|
@ -303,7 +299,6 @@ pub fn confirmation_by_lite_rpc_notification_stream(
|
||||||
vec![confirming_task, cleaner_jh]
|
vec![confirming_task, cleaner_jh]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated]
|
|
||||||
pub fn confirmations_by_blocks(
|
pub fn confirmations_by_blocks(
|
||||||
client: Arc<RpcClient>,
|
client: Arc<RpcClient>,
|
||||||
mut tx_record_rx: UnboundedReceiver<TransactionSendRecord>,
|
mut tx_record_rx: UnboundedReceiver<TransactionSendRecord>,
|
||||||
|
@ -383,7 +378,7 @@ pub fn confirmations_by_blocks(
|
||||||
timed_out: true,
|
timed_out: true,
|
||||||
priority_fees: sent_record.priority_fees,
|
priority_fees: sent_record.priority_fees,
|
||||||
});
|
});
|
||||||
to_remove.push(*signature);
|
to_remove.push(signature.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +396,7 @@ pub fn confirmations_by_blocks(
|
||||||
};
|
};
|
||||||
|
|
||||||
let block_confirmation_jh = {
|
let block_confirmation_jh = {
|
||||||
let exit_signal = exit_signal;
|
let exit_signal = exit_signal.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut start_block = from_slot;
|
let mut start_block = from_slot;
|
||||||
let mut start_instant = tokio::time::Instant::now();
|
let mut start_instant = tokio::time::Instant::now();
|
||||||
|
@ -460,7 +455,6 @@ pub fn confirmations_by_blocks(
|
||||||
tx_block_data,
|
tx_block_data,
|
||||||
transaction_map,
|
transaction_map,
|
||||||
block_slot.1,
|
block_slot.1,
|
||||||
commitment_confirmation.commitment,
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@ pub struct KeeperConfig {
|
||||||
pub websocket_url: String,
|
pub websocket_url: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub fn start(
|
pub fn start(
|
||||||
config: KeeperConfig,
|
config: KeeperConfig,
|
||||||
exit_signal: Arc<AtomicBool>,
|
exit_signal: Arc<AtomicBool>,
|
||||||
|
|
|
@ -55,7 +55,7 @@ pub fn to_sdk_instruction(
|
||||||
|
|
||||||
pub async fn load_from_rpc<T: Loadable>(rpc_client: &RpcClient, pk: &Pubkey) -> T {
|
pub async fn load_from_rpc<T: Loadable>(rpc_client: &RpcClient, pk: &Pubkey) -> T {
|
||||||
let acc = rpc_client.get_account(&to_sdk_pk(pk)).await.unwrap();
|
let acc = rpc_client.get_account(&to_sdk_pk(pk)).await.unwrap();
|
||||||
*T::load_from_bytes(acc.data.as_slice()).unwrap()
|
return T::load_from_bytes(acc.data.as_slice()).unwrap().clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_latest_blockhash(rpc_client: &RpcClient) -> Hash {
|
pub async fn get_latest_blockhash(rpc_client: &RpcClient) -> Hash {
|
||||||
|
@ -116,8 +116,10 @@ pub async fn poll_blockhash_and_slot(
|
||||||
*blockhash.write().await = new_blockhash;
|
*blockhash.write().await = new_blockhash;
|
||||||
}
|
}
|
||||||
blockhash_last_updated = Instant::now();
|
blockhash_last_updated = Instant::now();
|
||||||
} else if blockhash_last_updated.elapsed().as_secs() > 120 {
|
} else {
|
||||||
break;
|
if blockhash_last_updated.elapsed().as_secs() > 120 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||||
|
@ -196,7 +198,7 @@ pub async fn get_mango_market_perps_cache(
|
||||||
order_base_lots,
|
order_base_lots,
|
||||||
price,
|
price,
|
||||||
price_quote_lots,
|
price_quote_lots,
|
||||||
mango_program_pk: *mango_program_pk,
|
mango_program_pk: mango_program_pk.clone(),
|
||||||
mango_group_pk,
|
mango_group_pk,
|
||||||
mango_cache_pk,
|
mango_cache_pk,
|
||||||
perp_market_pk,
|
perp_market_pk,
|
||||||
|
|
|
@ -131,7 +131,7 @@ pub fn prepare_transaction(
|
||||||
priority_fees: prioritization_fee,
|
priority_fees: prioritization_fee,
|
||||||
keeper_instruction: Some(keeper_instruction),
|
keeper_instruction: Some(keeper_instruction),
|
||||||
};
|
};
|
||||||
(tx, tx_send_record)
|
return (tx, tx_send_record);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_update_and_cache_quote_banks(
|
pub fn create_update_and_cache_quote_banks(
|
||||||
|
@ -161,7 +161,6 @@ pub fn create_update_and_cache_quote_banks(
|
||||||
vec![to_sdk_instruction(ix_update), to_sdk_instruction(ix_cache)]
|
vec![to_sdk_instruction(ix_update), to_sdk_instruction(ix_cache)]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub fn start_keepers(
|
pub fn start_keepers(
|
||||||
exit_signal: Arc<AtomicBool>,
|
exit_signal: Arc<AtomicBool>,
|
||||||
tpu_manager: TpuManager,
|
tpu_manager: TpuManager,
|
||||||
|
|
14
src/main.rs
14
src/main.rs
|
@ -16,6 +16,7 @@ use {
|
||||||
stats::MangoSimulationStats,
|
stats::MangoSimulationStats,
|
||||||
tpu_manager::TpuManager,
|
tpu_manager::TpuManager,
|
||||||
},
|
},
|
||||||
|
serde_json,
|
||||||
solana_client::nonblocking::rpc_client::RpcClient as NbRpcClient,
|
solana_client::nonblocking::rpc_client::RpcClient as NbRpcClient,
|
||||||
solana_lite_rpc_core::{
|
solana_lite_rpc_core::{
|
||||||
block_store::BlockStore,
|
block_store::BlockStore,
|
||||||
|
@ -104,8 +105,7 @@ pub async fn main() -> anyhow::Result<()> {
|
||||||
solana_logger::setup_with_default("info");
|
solana_logger::setup_with_default("info");
|
||||||
solana_metrics::set_panic_hook("bench-mango", /*version:*/ None);
|
solana_metrics::set_panic_hook("bench-mango", /*version:*/ None);
|
||||||
|
|
||||||
let version = solana_version::version!();
|
let matches = cli::build_args(solana_version::version!()).get_matches();
|
||||||
let matches = cli::build_args(version).get_matches();
|
|
||||||
let cli_config = cli::extract_args(&matches);
|
let cli_config = cli::extract_args(&matches);
|
||||||
|
|
||||||
let cli::Config {
|
let cli::Config {
|
||||||
|
@ -153,14 +153,13 @@ pub async fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
let nb_rpc_client = Arc::new(NbRpcClient::new_with_commitment(
|
let nb_rpc_client = Arc::new(NbRpcClient::new_with_commitment(
|
||||||
json_rpc_url.to_string(),
|
json_rpc_url.to_string(),
|
||||||
CommitmentConfig::finalized(),
|
CommitmentConfig::confirmed(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let tx_store = empty_tx_store();
|
let tx_store = empty_tx_store();
|
||||||
let block_store = BlockStore::new(&nb_rpc_client)
|
let block_store = BlockStore::new(&nb_rpc_client)
|
||||||
.await
|
.await
|
||||||
.expect("Blockstore should be created");
|
.expect("Blockstore should be created");
|
||||||
|
|
||||||
let (notif_sx, notif_rx) = unbounded_channel();
|
let (notif_sx, notif_rx) = unbounded_channel();
|
||||||
let (transaction_service, tx_service_jh) = configure_transaction_service(
|
let (transaction_service, tx_service_jh) = configure_transaction_service(
|
||||||
nb_rpc_client.clone(),
|
nb_rpc_client.clone(),
|
||||||
|
@ -206,7 +205,9 @@ pub async fn main() -> anyhow::Result<()> {
|
||||||
account_keys_parsed.len(),
|
account_keys_parsed.len(),
|
||||||
number_of_markers_per_mm,
|
number_of_markers_per_mm,
|
||||||
quotes_per_second,
|
quotes_per_second,
|
||||||
account_keys_parsed.len() * number_of_markers_per_mm as usize * *quotes_per_second as usize,
|
account_keys_parsed.len()
|
||||||
|
* number_of_markers_per_mm as usize
|
||||||
|
* quotes_per_second.clone() as usize,
|
||||||
duration
|
duration
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -219,6 +220,7 @@ pub async fn main() -> anyhow::Result<()> {
|
||||||
let quote_root_bank =
|
let quote_root_bank =
|
||||||
Pubkey::from_str(mango_group_config.tokens.last().unwrap().root_key.as_str())
|
Pubkey::from_str(mango_group_config.tokens.last().unwrap().root_key.as_str())
|
||||||
.expect("Quote root bank should be able to convert into pubkey");
|
.expect("Quote root bank should be able to convert into pubkey");
|
||||||
|
();
|
||||||
let quote_node_banks = mango_group_config
|
let quote_node_banks = mango_group_config
|
||||||
.tokens
|
.tokens
|
||||||
.last()
|
.last()
|
||||||
|
@ -284,7 +286,7 @@ pub async fn main() -> anyhow::Result<()> {
|
||||||
blockhash.clone(),
|
blockhash.clone(),
|
||||||
current_slot.clone(),
|
current_slot.clone(),
|
||||||
tpu_manager.clone(),
|
tpu_manager.clone(),
|
||||||
duration,
|
&duration,
|
||||||
*quotes_per_second,
|
*quotes_per_second,
|
||||||
*priority_fees_proba,
|
*priority_fees_proba,
|
||||||
number_of_markers_per_mm,
|
number_of_markers_per_mm,
|
||||||
|
|
|
@ -45,7 +45,7 @@ impl MangoV3PerpCrankSink {
|
||||||
Self {
|
Self {
|
||||||
mkt_pks_by_evq_pks: pks
|
mkt_pks_by_evq_pks: pks
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(mkt_pk, evq_pk)| (*evq_pk, *mkt_pk))
|
.map(|(mkt_pk, evq_pk)| (evq_pk.clone(), mkt_pk.clone()))
|
||||||
.collect(),
|
.collect(),
|
||||||
group_pk,
|
group_pk,
|
||||||
cache_pk,
|
cache_pk,
|
||||||
|
@ -73,7 +73,7 @@ impl AccountWriteSink for MangoV3PerpCrankSink {
|
||||||
const HEADER_SIZE: usize = size_of::<EventQueueHeader>();
|
const HEADER_SIZE: usize = size_of::<EventQueueHeader>();
|
||||||
let header_data = array_ref![account.data(), 0, HEADER_SIZE];
|
let header_data = array_ref![account.data(), 0, HEADER_SIZE];
|
||||||
let header = RefCell::<EventQueueHeader>::new(*bytemuck::from_bytes(header_data));
|
let header = RefCell::<EventQueueHeader>::new(*bytemuck::from_bytes(header_data));
|
||||||
let seq_num = header.clone().into_inner().seq_num;
|
let seq_num = header.clone().into_inner().seq_num.clone();
|
||||||
// trace!("evq {} seq_num {}", mkt.name, header.seq_num);
|
// trace!("evq {} seq_num {}", mkt.name, header.seq_num);
|
||||||
|
|
||||||
const QUEUE_SIZE: usize = EVENT_SIZE * QUEUE_LEN;
|
const QUEUE_SIZE: usize = EVENT_SIZE * QUEUE_LEN;
|
||||||
|
@ -87,7 +87,8 @@ impl AccountWriteSink for MangoV3PerpCrankSink {
|
||||||
// only crank if at least 1 fill or a sufficient events of other categories are buffered
|
// only crank if at least 1 fill or a sufficient events of other categories are buffered
|
||||||
let contains_fill_events = event_queue
|
let contains_fill_events = event_queue
|
||||||
.iter()
|
.iter()
|
||||||
.any(|e| e.event_type == EventType::Fill as u8);
|
.find(|e| e.event_type == EventType::Fill as u8)
|
||||||
|
.is_some();
|
||||||
let len = event_queue.iter().count();
|
let len = event_queue.iter().count();
|
||||||
let has_backlog = len > MAX_BACKLOG;
|
let has_backlog = len > MAX_BACKLOG;
|
||||||
debug!("evq {pk:?} seq_num={seq_num} len={len} contains_fill_events={contains_fill_events} has_backlog={has_backlog}");
|
debug!("evq {pk:?} seq_num={seq_num} len={len} contains_fill_events={contains_fill_events} has_backlog={has_backlog}");
|
||||||
|
@ -120,7 +121,7 @@ impl AccountWriteSink for MangoV3PerpCrankSink {
|
||||||
let mkt_pk = self
|
let mkt_pk = self
|
||||||
.mkt_pks_by_evq_pks
|
.mkt_pks_by_evq_pks
|
||||||
.get(&pk)
|
.get(&pk)
|
||||||
.unwrap_or_else(|| panic!("{pk:?} is a known public key"));
|
.expect(&format!("{pk:?} is a known public key"));
|
||||||
|
|
||||||
let ix = to_sdk_instruction(
|
let ix = to_sdk_instruction(
|
||||||
consume_events(
|
consume_events(
|
||||||
|
@ -129,13 +130,16 @@ impl AccountWriteSink for MangoV3PerpCrankSink {
|
||||||
&to_sp_pk(&self.cache_pk),
|
&to_sp_pk(&self.cache_pk),
|
||||||
&to_sp_pk(mkt_pk),
|
&to_sp_pk(mkt_pk),
|
||||||
&to_sp_pk(&pk),
|
&to_sp_pk(&pk),
|
||||||
&mut mango_accounts.iter().copied().collect::<Vec<_>>(),
|
&mut mango_accounts
|
||||||
|
.iter()
|
||||||
|
.map(|pk| pk.clone())
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
MAX_EVENTS_PER_TX,
|
MAX_EVENTS_PER_TX,
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
(Ok(ix), *mkt_pk)
|
(Ok(ix), mkt_pk.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
// info!(
|
// info!(
|
||||||
|
|
|
@ -40,9 +40,8 @@ pub fn create_ask_bid_transaction(
|
||||||
prioritization_fee: u64,
|
prioritization_fee: u64,
|
||||||
) -> Transaction {
|
) -> Transaction {
|
||||||
let mango_account_signer_pk = to_sp_pk(&mango_account_signer.pubkey());
|
let mango_account_signer_pk = to_sp_pk(&mango_account_signer.pubkey());
|
||||||
let price = 100;
|
let offset = rand::random::<i8>() as i64;
|
||||||
let offset = rand::random::<i8>() as i64 % 20;
|
let spread = rand::random::<u8>() as i64;
|
||||||
let spread = rand::random::<u8>() as i64 % 10;
|
|
||||||
debug!(
|
debug!(
|
||||||
"price:{:?} price_quote_lots:{:?} order_base_lots:{:?} offset:{:?} spread:{:?}",
|
"price:{:?} price_quote_lots:{:?} order_base_lots:{:?} offset:{:?} spread:{:?}",
|
||||||
c.price, c.price_quote_lots, c.order_base_lots, offset, spread
|
c.price, c.price_quote_lots, c.order_base_lots, offset, spread
|
||||||
|
@ -83,7 +82,7 @@ pub fn create_ask_bid_transaction(
|
||||||
None,
|
None,
|
||||||
&[],
|
&[],
|
||||||
Side::Bid,
|
Side::Bid,
|
||||||
price + offset - spread,
|
c.price_quote_lots + offset - spread,
|
||||||
c.order_base_lots,
|
c.order_base_lots,
|
||||||
i64::MAX,
|
i64::MAX,
|
||||||
Utc::now().timestamp_micros() as u64,
|
Utc::now().timestamp_micros() as u64,
|
||||||
|
@ -111,7 +110,7 @@ pub fn create_ask_bid_transaction(
|
||||||
None,
|
None,
|
||||||
&[],
|
&[],
|
||||||
Side::Ask,
|
Side::Ask,
|
||||||
price + offset + spread,
|
c.price_quote_lots + offset + spread,
|
||||||
c.order_base_lots,
|
c.order_base_lots,
|
||||||
i64::MAX,
|
i64::MAX,
|
||||||
Utc::now().timestamp_micros() as u64,
|
Utc::now().timestamp_micros() as u64,
|
||||||
|
@ -144,19 +143,20 @@ fn generate_random_fees(
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
if prioritization_fee_proba == 0 {
|
if prioritization_fee_proba == 0 {
|
||||||
0
|
0
|
||||||
} else if range_probability.sample(&mut rng) <= prioritization_fee_proba {
|
|
||||||
range.sample(&mut rng)
|
|
||||||
} else {
|
} else {
|
||||||
0
|
if range_probability.sample(&mut rng) <= prioritization_fee_proba {
|
||||||
|
range.sample(&mut rng) as u64
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub async fn send_mm_transactions(
|
pub async fn send_mm_transactions(
|
||||||
quotes_per_second: u64,
|
quotes_per_second: u64,
|
||||||
perp_market_caches: &[PerpMarketCache],
|
perp_market_caches: &Vec<PerpMarketCache>,
|
||||||
tpu_manager: TpuManager,
|
tpu_manager: TpuManager,
|
||||||
mango_account_pk: Pubkey,
|
mango_account_pk: Pubkey,
|
||||||
mango_account_signer: &Keypair,
|
mango_account_signer: &Keypair,
|
||||||
|
@ -179,7 +179,7 @@ pub async fn send_mm_transactions(
|
||||||
let mut tx = create_ask_bid_transaction(
|
let mut tx = create_ask_bid_transaction(
|
||||||
c,
|
c,
|
||||||
mango_account_pk,
|
mango_account_pk,
|
||||||
mango_account_signer,
|
&mango_account_signer,
|
||||||
prioritization_fee,
|
prioritization_fee,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -207,7 +207,6 @@ pub async fn send_mm_transactions(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
|
||||||
pub fn start_market_making_threads(
|
pub fn start_market_making_threads(
|
||||||
account_keys_parsed: Vec<AccountKeys>,
|
account_keys_parsed: Vec<AccountKeys>,
|
||||||
perp_market_caches: Vec<PerpMarketCache>,
|
perp_market_caches: Vec<PerpMarketCache>,
|
||||||
|
@ -227,7 +226,7 @@ pub fn start_market_making_threads(
|
||||||
let exit_signal = exit_signal.clone();
|
let exit_signal = exit_signal.clone();
|
||||||
let blockhash = blockhash.clone();
|
let blockhash = blockhash.clone();
|
||||||
let current_slot = current_slot.clone();
|
let current_slot = current_slot.clone();
|
||||||
let duration = *duration;
|
let duration = duration.clone();
|
||||||
let perp_market_caches = perp_market_caches.clone();
|
let perp_market_caches = perp_market_caches.clone();
|
||||||
let mango_account_pk =
|
let mango_account_pk =
|
||||||
Pubkey::from_str(account_keys.mango_account_pks[0].as_str()).unwrap();
|
Pubkey::from_str(account_keys.mango_account_pks[0].as_str()).unwrap();
|
||||||
|
@ -242,7 +241,7 @@ pub fn start_market_making_threads(
|
||||||
);
|
);
|
||||||
let perp_market_caches = perp_market_caches
|
let perp_market_caches = perp_market_caches
|
||||||
.choose_multiple(&mut rng, number_of_markers_per_mm as usize)
|
.choose_multiple(&mut rng, number_of_markers_per_mm as usize)
|
||||||
.cloned()
|
.map(|x| x.clone())
|
||||||
.collect_vec();
|
.collect_vec();
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
@ -313,7 +312,7 @@ fn create_cancel_all_orders(
|
||||||
|
|
||||||
pub async fn clean_market_makers(
|
pub async fn clean_market_makers(
|
||||||
rpc_client: Arc<RpcClient>,
|
rpc_client: Arc<RpcClient>,
|
||||||
account_keys_parsed: &[AccountKeys],
|
account_keys_parsed: &Vec<AccountKeys>,
|
||||||
perp_market_caches: &Vec<PerpMarketCache>,
|
perp_market_caches: &Vec<PerpMarketCache>,
|
||||||
blockhash: Arc<RwLock<Hash>>,
|
blockhash: Arc<RwLock<Hash>>,
|
||||||
) {
|
) {
|
||||||
|
@ -324,11 +323,11 @@ pub async fn clean_market_makers(
|
||||||
for market_maker in account_keys_parsed {
|
for market_maker in account_keys_parsed {
|
||||||
let mango_account_pk =
|
let mango_account_pk =
|
||||||
Pubkey::from_str(market_maker.mango_account_pks[0].as_str()).unwrap();
|
Pubkey::from_str(market_maker.mango_account_pks[0].as_str()).unwrap();
|
||||||
|
|
||||||
for perp_market in perp_market_caches {
|
for perp_market in perp_market_caches {
|
||||||
let market_maker = market_maker.clone();
|
let market_maker = market_maker.clone();
|
||||||
let perp_market = perp_market.clone();
|
let perp_market = perp_market.clone();
|
||||||
let rpc_client = rpc_client.clone();
|
let rpc_client = rpc_client.clone();
|
||||||
|
let mango_account_pk = mango_account_pk.clone();
|
||||||
let blockhash = blockhash.clone();
|
let blockhash = blockhash.clone();
|
||||||
|
|
||||||
let task = tokio::spawn(async move {
|
let task = tokio::spawn(async move {
|
||||||
|
|
|
@ -16,8 +16,12 @@ pub fn initialize_result_writers(
|
||||||
File::create(transaction_save_file).await.unwrap(),
|
File::create(transaction_save_file).await.unwrap(),
|
||||||
);
|
);
|
||||||
let mut tx_data = tx_data;
|
let mut tx_data = tx_data;
|
||||||
while let Ok(record) = tx_data.recv().await {
|
loop {
|
||||||
writer.serialize(record).await.unwrap();
|
if let Ok(record) = tx_data.recv().await {
|
||||||
|
writer.serialize(record).await.unwrap();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
writer.flush().await.unwrap();
|
writer.flush().await.unwrap();
|
||||||
});
|
});
|
||||||
|
@ -30,8 +34,12 @@ pub fn initialize_result_writers(
|
||||||
File::create(block_data_save_file).await.unwrap(),
|
File::create(block_data_save_file).await.unwrap(),
|
||||||
);
|
);
|
||||||
let mut block_data = block_data;
|
let mut block_data = block_data;
|
||||||
while let Ok(record) = block_data.recv().await {
|
loop {
|
||||||
writer.serialize(record).await.unwrap();
|
if let Ok(record) = block_data.recv().await {
|
||||||
|
writer.serialize(record).await.unwrap();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
writer.flush().await.unwrap();
|
writer.flush().await.unwrap();
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,7 @@ use fixed::types::I80F48;
|
||||||
use mango::state::PerpMarket;
|
use mango::state::PerpMarket;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use solana_program::{pubkey::Pubkey, slot_history::Slot};
|
use solana_program::{pubkey::Pubkey, slot_history::Slot};
|
||||||
use solana_sdk::{commitment_config::CommitmentLevel, signature::Signature};
|
use solana_sdk::signature::Signature;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
@ -99,9 +99,7 @@ pub struct BlockData {
|
||||||
pub block_slot: Slot,
|
pub block_slot: Slot,
|
||||||
pub block_leader: String,
|
pub block_leader: String,
|
||||||
pub total_transactions: u64,
|
pub total_transactions: u64,
|
||||||
pub number_of_mango_simulation_txs: u64,
|
pub number_of_mm_transactions: u64,
|
||||||
pub block_time: u64,
|
pub block_time: u64,
|
||||||
pub cu_consumed: u64,
|
pub cu_consumed: u64,
|
||||||
pub cu_consumed_by_mango_simulations: u64,
|
|
||||||
pub commitment: CommitmentLevel,
|
|
||||||
}
|
}
|
||||||
|
|
88
src/stats.rs
88
src/stats.rs
|
@ -191,53 +191,57 @@ impl MangoSimulationStats {
|
||||||
let regex = regex::Regex::new(r"Error processing Instruction \d+: ").unwrap();
|
let regex = regex::Regex::new(r"Error processing Instruction \d+: ").unwrap();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut tx_confirm_record_reciever = tx_confirm_record_reciever;
|
let mut tx_confirm_record_reciever = tx_confirm_record_reciever;
|
||||||
while let Ok(tx_data) = tx_confirm_record_reciever.recv().await {
|
loop {
|
||||||
if tx_data.confirmed_at.is_some() {
|
if let Ok(tx_data) = tx_confirm_record_reciever.recv().await {
|
||||||
counters.num_confirmed_txs.fetch_add(1, Ordering::Relaxed);
|
if let Some(_) = tx_data.confirmed_at {
|
||||||
if let Some(error) = tx_data.error {
|
counters.num_confirmed_txs.fetch_add(1, Ordering::Relaxed);
|
||||||
let error = regex.replace_all(&error, "").to_string();
|
if let Some(error) = tx_data.error {
|
||||||
counters.num_error_txs.fetch_add(1, Ordering::Relaxed);
|
let error = regex.replace_all(&error, "").to_string();
|
||||||
let mut lock = counters.errors.write().await;
|
counters.num_error_txs.fetch_add(1, Ordering::Relaxed);
|
||||||
if let Some(value) = lock.get_mut(&error) {
|
let mut lock = counters.errors.write().await;
|
||||||
*value += 1;
|
if let Some(value) = lock.get_mut(&error) {
|
||||||
|
*value += 1;
|
||||||
|
} else {
|
||||||
|
lock.insert(error, 1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
lock.insert(error, 1);
|
counters.num_successful.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
|
if let Some(keeper_instruction) = tx_data.keeper_instruction {
|
||||||
|
match keeper_instruction {
|
||||||
|
KeeperInstruction::CachePrice => counters
|
||||||
|
.succ_cache_price_txs
|
||||||
|
.fetch_add(1, Ordering::Relaxed),
|
||||||
|
KeeperInstruction::CacheRootBanks => counters
|
||||||
|
.succ_cache_root_banks_txs
|
||||||
|
.fetch_add(1, Ordering::Relaxed),
|
||||||
|
KeeperInstruction::ConsumeEvents => counters
|
||||||
|
.succ_consume_events_txs
|
||||||
|
.fetch_add(1, Ordering::Relaxed),
|
||||||
|
KeeperInstruction::UpdateAndCacheQuoteRootBank => counters
|
||||||
|
.succ_update_and_cache_quote_bank_txs
|
||||||
|
.fetch_add(1, Ordering::Relaxed),
|
||||||
|
KeeperInstruction::UpdateFunding => counters
|
||||||
|
.succ_update_funding_txs
|
||||||
|
.fetch_add(1, Ordering::Relaxed),
|
||||||
|
KeeperInstruction::UpdatePerpCache => counters
|
||||||
|
.succ_update_perp_cache_txs
|
||||||
|
.fetch_add(1, Ordering::Relaxed),
|
||||||
|
KeeperInstruction::UpdateRootBanks => counters
|
||||||
|
.succ_update_root_banks_txs
|
||||||
|
.fetch_add(1, Ordering::Relaxed),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
counters
|
||||||
|
.succ_market_makers_txs
|
||||||
|
.fetch_add(1, Ordering::Relaxed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
counters.num_successful.fetch_add(1, Ordering::Relaxed);
|
counters.num_timeout_txs.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
if let Some(keeper_instruction) = tx_data.keeper_instruction {
|
|
||||||
match keeper_instruction {
|
|
||||||
KeeperInstruction::CachePrice => counters
|
|
||||||
.succ_cache_price_txs
|
|
||||||
.fetch_add(1, Ordering::Relaxed),
|
|
||||||
KeeperInstruction::CacheRootBanks => counters
|
|
||||||
.succ_cache_root_banks_txs
|
|
||||||
.fetch_add(1, Ordering::Relaxed),
|
|
||||||
KeeperInstruction::ConsumeEvents => counters
|
|
||||||
.succ_consume_events_txs
|
|
||||||
.fetch_add(1, Ordering::Relaxed),
|
|
||||||
KeeperInstruction::UpdateAndCacheQuoteRootBank => counters
|
|
||||||
.succ_update_and_cache_quote_bank_txs
|
|
||||||
.fetch_add(1, Ordering::Relaxed),
|
|
||||||
KeeperInstruction::UpdateFunding => counters
|
|
||||||
.succ_update_funding_txs
|
|
||||||
.fetch_add(1, Ordering::Relaxed),
|
|
||||||
KeeperInstruction::UpdatePerpCache => counters
|
|
||||||
.succ_update_perp_cache_txs
|
|
||||||
.fetch_add(1, Ordering::Relaxed),
|
|
||||||
KeeperInstruction::UpdateRootBanks => counters
|
|
||||||
.succ_update_root_banks_txs
|
|
||||||
.fetch_add(1, Ordering::Relaxed),
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
counters
|
|
||||||
.succ_market_makers_txs
|
|
||||||
.fetch_add(1, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
counters.num_timeout_txs.fetch_add(1, Ordering::Relaxed);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -47,15 +47,10 @@ impl TpuManager {
|
||||||
}
|
}
|
||||||
let transaction = bincode::serialize(transaction).unwrap();
|
let transaction = bincode::serialize(transaction).unwrap();
|
||||||
|
|
||||||
let res = self
|
self.transaction_service
|
||||||
.transaction_service
|
|
||||||
.send_transaction(transaction, None)
|
.send_transaction(transaction, None)
|
||||||
.await;
|
.await
|
||||||
|
.is_ok()
|
||||||
if let Err(e) = &res {
|
|
||||||
print!("error sending txs on custom tpu {e:?}");
|
|
||||||
}
|
|
||||||
res.is_ok()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_transaction_batch(
|
pub async fn send_transaction_batch(
|
||||||
|
|
Loading…
Reference in New Issue