Merge pull request #15 from blockworks-foundation/max/fix-crank
improve integrated keeper & crank reliability
This commit is contained in:
commit
a0719a8eb9
|
@ -3189,7 +3189,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "mango-feeds-connector"
|
||||
version = "0.1.1"
|
||||
source = "git+https://github.com/blockworks-foundation/mango-feeds.git?branch=ckamm/solana-versions2#4cc67d34df40d12070ba0c311ca68f8c00c3ab1f"
|
||||
source = "git+https://github.com/blockworks-foundation/mango-feeds.git?branch=ckamm/solana-versions2#613b2b2f799d2fab31134ec1366b270c0eacdbd2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-channel",
|
||||
|
|
17
src/crank.rs
17
src/crank.rs
|
@ -2,6 +2,7 @@ use crate::{
|
|||
helpers::to_sp_pk,
|
||||
mango::GroupConfig,
|
||||
mango_v3_perp_crank_sink::MangoV3PerpCrankSink,
|
||||
noop,
|
||||
states::{KeeperInstruction, TransactionSendRecord},
|
||||
tpu_manager::TpuManager,
|
||||
};
|
||||
|
@ -58,7 +59,7 @@ pub fn start(
|
|||
let group_pk = Pubkey::from_str(&group.public_key).unwrap();
|
||||
let cache_pk = Pubkey::from_str(&group.cache_key).unwrap();
|
||||
let mango_program_id = Pubkey::from_str(&group.mango_program_id).unwrap();
|
||||
let _filter_config = FilterConfig {
|
||||
let filter_config = FilterConfig {
|
||||
program_ids: vec![group.mango_program_id.clone()],
|
||||
account_ids: group
|
||||
.perp_markets
|
||||
|
@ -79,8 +80,17 @@ pub fn start(
|
|||
break;
|
||||
}
|
||||
|
||||
if let Ok((market, ixs)) = instruction_receiver.recv().await {
|
||||
// TODO add priority fee
|
||||
if let Ok((market, mut ixs)) = instruction_receiver.recv().await {
|
||||
// add priority fees
|
||||
ixs.push(
|
||||
solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_price(
|
||||
prioritization_fee,
|
||||
),
|
||||
);
|
||||
// add timestamp to guarantee unique transactions
|
||||
ixs.push(noop::instruction(
|
||||
Utc::now().timestamp_micros().to_le_bytes().into(),
|
||||
));
|
||||
|
||||
let tx = Transaction::new_signed_with_payer(
|
||||
&ixs,
|
||||
|
@ -163,6 +173,7 @@ pub fn start(
|
|||
},
|
||||
rpc_ws_url: config.websocket_url,
|
||||
},
|
||||
&filter_config,
|
||||
account_write_queue_sender,
|
||||
slot_queue_sender,
|
||||
)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
helpers::to_sdk_instruction,
|
||||
noop,
|
||||
states::{KeeperInstruction, PerpMarketCache, TransactionSendRecord},
|
||||
tpu_manager::TpuManager,
|
||||
},
|
||||
|
@ -102,14 +103,22 @@ fn create_cache_perp_markets_instructions(perp_markets: &[PerpMarketCache]) -> I
|
|||
|
||||
pub async fn send_transaction(
|
||||
tpu_manager: TpuManager,
|
||||
ixs: &[Instruction],
|
||||
mut ixs: Vec<Instruction>,
|
||||
blockhash: Arc<RwLock<Hash>>,
|
||||
current_slot: Arc<AtomicU64>,
|
||||
payer: &Keypair,
|
||||
prioritization_fee: u64,
|
||||
keeper_instruction: KeeperInstruction,
|
||||
) {
|
||||
let mut tx = Transaction::new_unsigned(Message::new(ixs, Some(&payer.pubkey())));
|
||||
// add a noop with a current timestamp to ensure unique txs
|
||||
ixs.push(noop::instruction(Utc::now().timestamp_micros().to_le_bytes().into()));
|
||||
// add priority fees
|
||||
ixs.push(
|
||||
solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_price(
|
||||
prioritization_fee,
|
||||
),
|
||||
);
|
||||
let mut tx = Transaction::new_unsigned(Message::new(&ixs, Some(&payer.pubkey())));
|
||||
let recent_blockhash = blockhash.read().await;
|
||||
tx.sign(&[payer], *recent_blockhash);
|
||||
|
||||
|
@ -167,38 +176,20 @@ pub fn start_keepers(
|
|||
tokio::spawn(async move {
|
||||
let current_slot = current_slot.clone();
|
||||
|
||||
let prioritization_fee_ix =
|
||||
solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_price(
|
||||
prioritization_fee,
|
||||
);
|
||||
|
||||
let mut root_update_ixs = create_root_bank_update_instructions(&perp_markets);
|
||||
let mut cache_prices = vec![create_update_price_cache_instructions(&perp_markets)];
|
||||
let mut update_perp_cache = vec![create_cache_perp_markets_instructions(&perp_markets)];
|
||||
let mut cache_root_bank_ix = vec![create_cache_root_bank_instruction(&perp_markets)];
|
||||
let mut update_funding_ix = create_update_fundings_instructions(&perp_markets);
|
||||
let mut quote_root_bank_ix =
|
||||
let root_update_ixs = create_root_bank_update_instructions(&perp_markets);
|
||||
let cache_prices = vec![create_update_price_cache_instructions(&perp_markets)];
|
||||
let update_perp_cache = vec![create_cache_perp_markets_instructions(&perp_markets)];
|
||||
let cache_root_bank_ix = vec![create_cache_root_bank_instruction(&perp_markets)];
|
||||
let update_funding_ix = create_update_fundings_instructions(&perp_markets);
|
||||
let quote_root_bank_ix =
|
||||
create_update_and_cache_quote_banks(&perp_markets, quote_root_bank, quote_node_banks);
|
||||
|
||||
if prioritization_fee > 0 {
|
||||
root_update_ixs.insert(0, prioritization_fee_ix.clone());
|
||||
cache_prices.insert(0, prioritization_fee_ix.clone());
|
||||
update_perp_cache.insert(0, prioritization_fee_ix.clone());
|
||||
cache_root_bank_ix.insert(0, prioritization_fee_ix.clone());
|
||||
update_funding_ix.insert(0, prioritization_fee_ix.clone());
|
||||
quote_root_bank_ix.insert(0, prioritization_fee_ix.clone());
|
||||
}
|
||||
|
||||
let blockhash = blockhash.clone();
|
||||
|
||||
// add prioritization instruction
|
||||
//let prioritization_ix = ComputeBudgetInstruction::set_compute_unit_price(10000);
|
||||
//root_update_ixs.insert(0, prioritization_ix.clone());
|
||||
|
||||
while !exit_signal.load(Ordering::Relaxed) {
|
||||
send_transaction(
|
||||
tpu_manager.clone(),
|
||||
cache_prices.as_slice(),
|
||||
cache_prices.clone(),
|
||||
blockhash.clone(),
|
||||
current_slot.clone(),
|
||||
&authority,
|
||||
|
@ -209,7 +200,7 @@ pub fn start_keepers(
|
|||
|
||||
send_transaction(
|
||||
tpu_manager.clone(),
|
||||
quote_root_bank_ix.as_slice(),
|
||||
quote_root_bank_ix.clone(),
|
||||
blockhash.clone(),
|
||||
current_slot.clone(),
|
||||
&authority,
|
||||
|
@ -221,7 +212,7 @@ pub fn start_keepers(
|
|||
for updates in update_funding_ix.chunks(3) {
|
||||
send_transaction(
|
||||
tpu_manager.clone(),
|
||||
updates,
|
||||
updates.to_vec(),
|
||||
blockhash.clone(),
|
||||
current_slot.clone(),
|
||||
&authority,
|
||||
|
@ -233,7 +224,7 @@ pub fn start_keepers(
|
|||
|
||||
send_transaction(
|
||||
tpu_manager.clone(),
|
||||
root_update_ixs.as_slice(),
|
||||
root_update_ixs.clone(),
|
||||
blockhash.clone(),
|
||||
current_slot.clone(),
|
||||
&authority,
|
||||
|
@ -244,7 +235,7 @@ pub fn start_keepers(
|
|||
|
||||
send_transaction(
|
||||
tpu_manager.clone(),
|
||||
update_perp_cache.as_slice(),
|
||||
update_perp_cache.clone(),
|
||||
blockhash.clone(),
|
||||
current_slot.clone(),
|
||||
&authority,
|
||||
|
@ -255,7 +246,7 @@ pub fn start_keepers(
|
|||
|
||||
send_transaction(
|
||||
tpu_manager.clone(),
|
||||
cache_root_bank_ix.as_slice(),
|
||||
cache_root_bank_ix.clone(),
|
||||
blockhash.clone(),
|
||||
current_slot.clone(),
|
||||
&authority,
|
||||
|
|
|
@ -6,6 +6,7 @@ pub mod keeper;
|
|||
pub mod mango;
|
||||
pub mod mango_v3_perp_crank_sink;
|
||||
pub mod market_markers;
|
||||
pub mod noop;
|
||||
pub mod result_writer;
|
||||
pub mod rotating_queue;
|
||||
pub mod states;
|
||||
|
|
|
@ -182,7 +182,7 @@ pub async fn main() -> anyhow::Result<()> {
|
|||
0,
|
||||
);
|
||||
|
||||
let warmup_duration = Duration::from_secs(10);
|
||||
let warmup_duration = Duration::from_secs(20);
|
||||
info!("waiting for keepers to warmup for {warmup_duration:?}");
|
||||
tokio::time::sleep(warmup_duration).await;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{cell::RefCell, collections::BTreeMap, convert::TryFrom, mem::size_of};
|
||||
use std::{cell::RefCell, collections::{BTreeMap, HashSet}, convert::TryFrom, mem::size_of};
|
||||
|
||||
use arrayref::array_ref;
|
||||
use async_channel::Sender;
|
||||
|
@ -18,7 +18,8 @@ use mango_feeds_connector::{account_write_filter::AccountWriteSink, chain_data::
|
|||
use crate::helpers::{to_sdk_instruction, to_sp_pk};
|
||||
|
||||
const MAX_BACKLOG: usize = 2;
|
||||
const MAX_EVENTS_PER_TX: usize = 10;
|
||||
const MAX_ACCS_PER_TX: usize = 24;
|
||||
const MAX_EVENTS_PER_TX: usize = 50;
|
||||
|
||||
pub struct MangoV3PerpCrankSink {
|
||||
mkt_pks_by_evq_pks: BTreeMap<Pubkey, Pubkey>,
|
||||
|
@ -93,23 +94,28 @@ impl AccountWriteSink for MangoV3PerpCrankSink {
|
|||
|
||||
trace!("evq {pk:?} seq_num={seq_num} len={len} contains_fill_events={contains_fill_events} has_backlog={has_backlog}");
|
||||
|
||||
let mut mango_accounts: Vec<_> = event_queue
|
||||
let mut mango_accounts = HashSet::new();
|
||||
event_queue
|
||||
.iter()
|
||||
.take(MAX_EVENTS_PER_TX)
|
||||
.flat_map(
|
||||
|e| match EventType::try_from(e.event_type).expect("mango v4 event") {
|
||||
EventType::Fill => {
|
||||
let fill: &FillEvent = cast_ref(e);
|
||||
vec![fill.maker, fill.taker]
|
||||
.for_each(|e|
|
||||
if mango_accounts.len() < MAX_ACCS_PER_TX {
|
||||
match EventType::try_from(e.event_type).expect("mango v4 event") {
|
||||
EventType::Fill => {
|
||||
let fill: &FillEvent = cast_ref(e);
|
||||
mango_accounts.insert(fill.maker);
|
||||
mango_accounts.insert(fill.taker);
|
||||
}
|
||||
EventType::Out => {
|
||||
let out: &OutEvent = cast_ref(e);
|
||||
mango_accounts.insert(out.owner);
|
||||
}
|
||||
EventType::Liquidate => {
|
||||
|
||||
}
|
||||
}
|
||||
EventType::Out => {
|
||||
let out: &OutEvent = cast_ref(e);
|
||||
vec![out.owner]
|
||||
}
|
||||
EventType::Liquidate => vec![],
|
||||
},
|
||||
)
|
||||
.collect();
|
||||
}
|
||||
);
|
||||
|
||||
let pk = solana_sdk::pubkey::Pubkey::new_from_array(pk.to_bytes());
|
||||
let mkt_pk = self
|
||||
|
@ -124,7 +130,7 @@ impl AccountWriteSink for MangoV3PerpCrankSink {
|
|||
&to_sp_pk(&self.cache_pk),
|
||||
&to_sp_pk(mkt_pk),
|
||||
&to_sp_pk(&pk),
|
||||
&mut mango_accounts,
|
||||
&mut mango_accounts.iter().map(|pk| pk.clone()).collect::<Vec<_>>(),
|
||||
MAX_EVENTS_PER_TX,
|
||||
)
|
||||
.unwrap(),
|
||||
|
|
|
@ -81,7 +81,7 @@ pub fn create_ask_bid_transaction(
|
|||
c.price_quote_lots + offset - spread,
|
||||
c.order_base_lots,
|
||||
i64::MAX,
|
||||
1,
|
||||
Utc::now().timestamp_micros() as u64,
|
||||
mango::matching::OrderType::Limit,
|
||||
false,
|
||||
None,
|
||||
|
@ -109,7 +109,7 @@ pub fn create_ask_bid_transaction(
|
|||
c.price_quote_lots + offset + spread,
|
||||
c.order_base_lots,
|
||||
i64::MAX,
|
||||
2,
|
||||
Utc::now().timestamp_micros() as u64,
|
||||
mango::matching::OrderType::Limit,
|
||||
false,
|
||||
None,
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
use std::str::FromStr;
|
||||
|
||||
use solana_sdk::{pubkey::Pubkey, instruction::Instruction};
|
||||
|
||||
pub fn instruction(data: Vec<u8>) -> Instruction {
|
||||
Instruction {
|
||||
program_id: Pubkey::from_str("noopb9bkMVfRPU8AsbpTUg8AQkHtKwMYZiFUjNRtMmV").unwrap(),
|
||||
accounts: vec![],
|
||||
data,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue