Merge pull request #15 from blockworks-foundation/max/fix-crank

improve integrated keeper & crank reliability
This commit is contained in:
Maximilian Schneider 2023-04-14 17:20:48 +02:00 committed by GitHub
commit a0719a8eb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 76 additions and 56 deletions

2
Cargo.lock generated
View File

@ -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",

View File

@ -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,
)

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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(),

View File

@ -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,

11
src/noop.rs Normal file
View File

@ -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,
}
}