mango-simulation/src/crank.rs

180 lines
5.5 KiB
Rust
Raw Normal View History

2023-02-18 08:22:12 -08:00
use crate::{
helpers::to_sp_pk,
2023-02-18 08:22:12 -08:00
mango::GroupConfig,
mango_v3_perp_crank_sink::MangoV3PerpCrankSink,
2023-04-14 05:04:35 -07:00
noop,
states::{KeeperInstruction, TransactionSendRecord},
tpu_manager::TpuManager,
2023-02-18 08:22:12 -08:00
};
2023-04-05 10:06:58 -07:00
use mango_feeds_connector::{
account_write_filter::{self, AccountWriteRoute},
2023-04-06 07:52:14 -07:00
metrics, websocket_source, FilterConfig, MetricsConfig, SnapshotSourceConfig, SourceConfig,
2023-04-05 10:06:58 -07:00
};
2023-03-14 05:39:19 -07:00
use async_channel::unbounded;
use chrono::Utc;
use log::*;
2023-03-09 07:20:49 -08:00
use solana_sdk::{
2023-04-14 05:18:04 -07:00
compute_budget::ComputeBudgetInstruction, hash::Hash, instruction::Instruction, pubkey::Pubkey,
signature::Keypair, signer::Signer, transaction::Transaction,
2023-03-09 07:20:49 -08:00
};
2023-03-14 05:39:19 -07:00
use std::{
str::FromStr,
sync::{
atomic::{AtomicBool, AtomicU64, Ordering},
Arc,
},
time::Duration,
};
use tokio::sync::RwLock;
2023-02-18 08:22:12 -08:00
2023-04-05 10:06:58 -07:00
#[derive(Debug, Clone)]
pub struct KeeperConfig {
pub program_id: Pubkey,
pub rpc_url: String,
pub websocket_url: String,
}
pub fn start(
config: KeeperConfig,
exit_signal: Arc<AtomicBool>,
blockhash: Arc<RwLock<Hash>>,
current_slot: Arc<AtomicU64>,
tpu_manager: TpuManager,
group: &GroupConfig,
identity: &Keypair,
prioritization_fee: u64,
) {
2023-02-18 08:22:12 -08:00
let perp_queue_pks: Vec<_> = group
.perp_markets
.iter()
.map(|m| {
(
Pubkey::from_str(&m.public_key).unwrap(),
Pubkey::from_str(&m.events_key).unwrap(),
)
})
.collect();
let group_pk = Pubkey::from_str(&group.public_key).unwrap();
let cache_pk = Pubkey::from_str(&group.cache_key).unwrap();
2023-02-18 08:22:12 -08:00
let mango_program_id = Pubkey::from_str(&group.mango_program_id).unwrap();
2023-04-13 08:38:53 -07:00
let filter_config = FilterConfig {
program_ids: vec![group.mango_program_id.clone()],
2023-03-09 07:20:49 -08:00
account_ids: group
.perp_markets
.iter()
.map(|m| m.events_key.clone())
.collect(),
2023-02-18 08:22:12 -08:00
};
let (instruction_sender, instruction_receiver) = unbounded::<(Pubkey, Vec<Instruction>)>();
let identity = Keypair::from_bytes(identity.to_bytes().as_slice()).unwrap();
2023-03-14 05:39:19 -07:00
tokio::spawn(async move {
info!(
"crank-tx-sender signing with keypair pk={:?}",
identity.pubkey()
);
2023-03-14 05:39:19 -07:00
loop {
if exit_signal.load(Ordering::Acquire) {
break;
}
2023-03-09 07:20:49 -08:00
2023-04-14 04:45:22 -07:00
if let Ok((market, mut ixs)) = instruction_receiver.recv().await {
2023-04-14 05:04:35 -07:00
// add priority fees
2023-04-14 05:18:04 -07:00
ixs.push(ComputeBudgetInstruction::set_compute_unit_price(
prioritization_fee,
2023-04-14 05:04:35 -07:00
));
2023-04-14 05:18:04 -07:00
// add timestamp to guarantee unique transactions
ixs.push(noop::timestamp());
2023-04-14 04:45:22 -07:00
2023-03-14 05:39:19 -07:00
let tx = Transaction::new_signed_with_payer(
&ixs,
Some(&identity.pubkey()),
&[&identity],
*blockhash.read().await,
);
let tx_send_record = TransactionSendRecord {
signature: tx.signatures[0],
sent_at: Utc::now(),
sent_slot: current_slot.load(Ordering::Acquire),
market_maker: None,
market: Some(to_sp_pk(&market)),
priority_fees: prioritization_fee,
keeper_instruction: Some(KeeperInstruction::ConsumeEvents),
};
2023-04-23 06:07:44 -07:00
let tpu_manager = tpu_manager.clone();
tpu_manager.send_transaction(&tx, tx_send_record).await;
}
2023-03-14 05:39:19 -07:00
}
});
tokio::spawn(async move {
2023-03-09 07:20:49 -08:00
let metrics_tx = metrics::start(
2023-04-05 10:06:58 -07:00
MetricsConfig {
2023-03-09 07:20:49 -08:00
output_stdout: true,
output_http: false,
},
"crank".into(),
);
let routes = vec![AccountWriteRoute {
matched_pubkeys: perp_queue_pks
.iter()
2023-04-06 07:52:14 -07:00
.map(|(_, evq_pk)| {
mango_feeds_connector::solana_sdk::pubkey::Pubkey::new_from_array(
evq_pk.to_bytes(),
)
})
2023-03-09 07:20:49 -08:00
.collect(),
sink: Arc::new(MangoV3PerpCrankSink::new(
perp_queue_pks,
group_pk,
cache_pk,
mango_program_id,
instruction_sender,
)),
timeout_interval: Duration::default(),
}];
info!("matched_pks={:?}", routes[0].matched_pubkeys);
2023-03-09 07:20:49 -08:00
let (account_write_queue_sender, slot_queue_sender) =
account_write_filter::init(routes, metrics_tx.clone()).expect("filter initializes");
// info!("start processing grpc events");
2023-03-09 07:20:49 -08:00
// grpc_plugin_source::process_events(
// &config,
// &filter_config,
// account_write_queue_sender,
// slot_queue_sender,
// metrics_tx.clone(),
// ).await;
2023-04-06 07:52:14 -07:00
info!(
"start processing websocket events program_id={:?} ws_url={:?}",
config.program_id, config.websocket_url
);
2023-03-09 07:20:49 -08:00
websocket_source::process_events(
2023-04-05 10:06:58 -07:00
&SourceConfig {
dedup_queue_size: 0,
grpc_sources: vec![],
snapshot: SnapshotSourceConfig {
rpc_http_url: config.rpc_url,
program_id: config.program_id.to_string(),
},
rpc_ws_url: config.websocket_url,
},
2023-04-13 08:38:53 -07:00
&filter_config,
2023-03-09 07:20:49 -08:00
account_write_queue_sender,
slot_queue_sender,
)
.await;
});
2023-02-18 08:22:12 -08:00
}