2023-02-18 08:22:12 -08:00
|
|
|
use crate::{
|
2023-03-15 08:13:25 -07:00
|
|
|
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,
|
2023-03-15 08:13:25 -07:00
|
|
|
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;
|
2023-03-15 08:13:25 -07:00
|
|
|
use chrono::Utc;
|
2023-03-09 07:08:03 -08:00
|
|
|
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,
|
|
|
|
};
|
2023-03-15 08:13:25 -07:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
|
2023-03-06 00:37:42 -08:00
|
|
|
pub fn start(
|
2023-03-10 04:38:11 -08:00
|
|
|
config: KeeperConfig,
|
2023-03-06 00:37:42 -08:00
|
|
|
exit_signal: Arc<AtomicBool>,
|
|
|
|
blockhash: Arc<RwLock<Hash>>,
|
2023-03-15 08:13:25 -07:00
|
|
|
current_slot: Arc<AtomicU64>,
|
|
|
|
tpu_manager: TpuManager,
|
2023-03-06 00:37:42 -08:00
|
|
|
group: &GroupConfig,
|
|
|
|
identity: &Keypair,
|
2023-03-15 08:13:25 -07:00
|
|
|
prioritization_fee: u64,
|
2023-03-06 00:37:42 -08:00
|
|
|
) {
|
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();
|
2023-03-06 00:37:42 -08:00
|
|
|
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 {
|
2023-03-06 00:37:42 -08:00
|
|
|
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
|
|
|
};
|
|
|
|
|
2023-03-15 08:13:25 -07:00
|
|
|
let (instruction_sender, instruction_receiver) = unbounded::<(Pubkey, Vec<Instruction>)>();
|
2023-03-06 00:37:42 -08:00
|
|
|
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-04-15 03:39:26 -07:00
|
|
|
|
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,
|
|
|
|
);
|
2023-03-15 08:13:25 -07:00
|
|
|
|
|
|
|
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();
|
2023-06-15 01:41:58 -07:00
|
|
|
tpu_manager.send_transaction(&tx, tx_send_record).await;
|
2023-03-06 00:37:42 -08:00
|
|
|
}
|
2023-03-14 05:39:19 -07:00
|
|
|
}
|
|
|
|
});
|
2023-03-06 00:37:42 -08: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(),
|
|
|
|
}];
|
|
|
|
|
2023-04-06 05:22:52 -07:00
|
|
|
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");
|
|
|
|
|
2023-04-06 05:22:52 -07:00
|
|
|
// 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-04-06 05:22:52 -07:00
|
|
|
|
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
|
|
|
}
|