mango-v4/programs/mango-v4/src/state/orderbook/bookside.rs

469 lines
16 KiB
Rust

use bytemuck::Zeroable;
use std::cell::RefMut;
use anchor_lang::prelude::*;
use bytemuck::{cast, cast_mut, cast_ref};
use num_enum::{IntoPrimitive, TryFromPrimitive};
use crate::state::orderbook::bookside_iterator::BookSideIter;
use crate::state::PerpMarket;
use crate::error::MangoError;
use crate::state::orderbook::nodes::{
AnyNode, FreeNode, InnerNode, LeafNode, NodeHandle, NodeRef, NodeTag,
};
use crate::util::LoadZeroCopy;
use super::Book;
pub const MAX_BOOK_NODES: usize = 1024;
#[derive(
Eq,
PartialEq,
Copy,
Clone,
TryFromPrimitive,
IntoPrimitive,
Debug,
AnchorSerialize,
AnchorDeserialize,
)]
#[repr(u8)]
pub enum BookSideType {
Bids,
Asks,
}
/// A binary tree on AnyNode::key()
///
/// The key encodes the price in the top 64 bits.
#[account(zero_copy)]
pub struct BookSide {
// pub meta_data: MetaData,
// todo: do we want this type at this level?
pub book_side_type: BookSideType,
pub bump_index: usize,
pub free_list_len: usize,
pub free_list_head: NodeHandle,
pub root_node: NodeHandle,
pub leaf_count: usize,
pub nodes: [AnyNode; MAX_BOOK_NODES],
}
impl BookSide {
/// Iterate over all entries in the book filtering out invalid orders
///
/// smallest to highest for asks
/// highest to smallest for bids
pub fn iter_valid(&self, now_ts: u64) -> BookSideIter {
BookSideIter::new(self, now_ts)
}
/// Iterate over all entries, including invalid orders
pub fn iter_all_including_invalid(&self) -> BookSideIter {
BookSideIter::new(self, 0)
}
pub fn load_mut_checked<'a>(
account: &'a AccountInfo,
perp_market: &PerpMarket,
) -> Result<RefMut<'a, Self>> {
let state = account.load_mut::<BookSide>()?;
match state.book_side_type {
BookSideType::Bids => require!(account.key == &perp_market.bids, MangoError::SomeError),
BookSideType::Asks => require!(account.key == &perp_market.asks, MangoError::SomeError),
}
Ok(state)
}
//
// pub fn load_and_init<'a>(
// account: &'a AccountInfo,
// program_id: &Pubkey,
// data_type: DataType,
// rent: &Rent,
// ) -> MangoResult<RefMut<'a, Self>> {
// // NOTE: require this first so we can borrow account later
// require!(
// rent.is_exempt(account.lamports(), account.data_len()),
// MangoErrorCode::AccountNotRentExempt
// )?;
//
// let mut state = Self::load_mut(account)?;
// require!(account.owner == program_id, MangoError::SomeError)?; // todo invalid owner
// require!(!state.meta_data.is_initialized, MangoError::SomeError)?; // todo
// state.meta_data = MetaData::new(data_type, 0, true);
// Ok(state)
// }
pub fn get_mut(&mut self, key: NodeHandle) -> Option<&mut AnyNode> {
let node = &mut self.nodes[key as usize];
let tag = NodeTag::try_from(node.tag);
match tag {
Ok(NodeTag::InnerNode) | Ok(NodeTag::LeafNode) => Some(node),
_ => None,
}
}
pub fn get(&self, key: NodeHandle) -> Option<&AnyNode> {
let node = &self.nodes[key as usize];
let tag = NodeTag::try_from(node.tag);
match tag {
Ok(NodeTag::InnerNode) | Ok(NodeTag::LeafNode) => Some(node),
_ => None,
}
}
pub fn remove_min(&mut self) -> Option<LeafNode> {
self.remove_by_key(self.get(self.find_min()?)?.key()?)
}
pub fn remove_max(&mut self) -> Option<LeafNode> {
self.remove_by_key(self.get(self.find_max()?)?.key()?)
}
/// Remove the order with the lowest expiry timestamp, if that's < now_ts.
pub fn remove_one_expired(&mut self, now_ts: u64) -> Option<LeafNode> {
let (expired_h, expires_at) = self.find_earliest_expiry()?;
if expires_at < now_ts {
self.remove_by_key(self.get(expired_h)?.key()?)
} else {
None
}
}
pub fn find_max(&self) -> Option<NodeHandle> {
self.find_min_max(true)
}
pub fn root(&self) -> Option<NodeHandle> {
if self.leaf_count == 0 {
None
} else {
Some(self.root_node)
}
}
pub fn find_min(&self) -> Option<NodeHandle> {
self.find_min_max(false)
}
#[cfg(test)]
fn to_price_quantity_vec(&self, reverse: bool) -> Vec<(i64, i64)> {
let mut pqs = vec![];
let mut current: NodeHandle = match self.root() {
None => return pqs,
Some(node_handle) => node_handle,
};
let left = reverse as usize;
let right = !reverse as usize;
let mut stack = vec![];
loop {
let root_contents = self.get(current).unwrap(); // should never fail unless book is already fucked
match root_contents.case().unwrap() {
NodeRef::Inner(inner) => {
stack.push(inner);
current = inner.children[left];
}
NodeRef::Leaf(leaf) => {
// if you hit leaf then pop stack and go right
// all inner nodes on stack have already been visited to the left
pqs.push((leaf.price(), leaf.quantity));
match stack.pop() {
None => return pqs,
Some(inner) => {
current = inner.children[right];
}
}
}
}
}
}
fn find_min_max(&self, find_max: bool) -> Option<NodeHandle> {
let mut root: NodeHandle = self.root()?;
let i = if find_max { 1 } else { 0 };
loop {
let root_contents = self.get(root).unwrap();
match root_contents.case().unwrap() {
NodeRef::Inner(&InnerNode { children, .. }) => {
root = children[i];
}
_ => return Some(root),
}
}
}
pub fn get_min(&self) -> Option<&LeafNode> {
self.get_min_max(false)
}
pub fn get_max(&self) -> Option<&LeafNode> {
self.get_min_max(true)
}
pub fn get_min_max(&self, find_max: bool) -> Option<&LeafNode> {
let mut root: NodeHandle = self.root()?;
let i = if find_max { 1 } else { 0 };
loop {
let root_contents = self.get(root)?;
match root_contents.case()? {
NodeRef::Inner(inner) => {
root = inner.children[i];
}
NodeRef::Leaf(leaf) => {
return Some(leaf);
}
}
}
}
pub fn remove_by_key(&mut self, search_key: i128) -> Option<LeafNode> {
// path of InnerNode handles that lead to the removed leaf
let mut stack: Vec<(NodeHandle, bool)> = vec![];
// special case potentially removing the root
let mut parent_h = self.root()?;
let (mut child_h, mut crit_bit) = match self.get(parent_h).unwrap().case().unwrap() {
NodeRef::Leaf(&leaf) if leaf.key == search_key => {
assert_eq!(self.leaf_count, 1);
self.root_node = 0;
self.leaf_count = 0;
let _old_root = self.remove(parent_h).unwrap();
return Some(leaf);
}
NodeRef::Leaf(_) => return None,
NodeRef::Inner(inner) => inner.walk_down(search_key),
};
stack.push((parent_h, crit_bit));
// walk down the tree until finding the key
loop {
match self.get(child_h).unwrap().case().unwrap() {
NodeRef::Inner(inner) => {
parent_h = child_h;
let (new_child_h, new_crit_bit) = inner.walk_down(search_key);
child_h = new_child_h;
crit_bit = new_crit_bit;
stack.push((parent_h, crit_bit));
}
NodeRef::Leaf(leaf) => {
if leaf.key != search_key {
return None;
}
break;
}
}
}
// replace parent with its remaining child node
// free child_h, replace *parent_h with *other_child_h, free other_child_h
let other_child_h = self.get(parent_h).unwrap().children().unwrap()[!crit_bit as usize];
let other_child_node_contents = self.remove(other_child_h).unwrap();
let new_expiry = other_child_node_contents.earliest_expiry();
*self.get_mut(parent_h).unwrap() = other_child_node_contents;
self.leaf_count -= 1;
let removed_leaf: LeafNode = cast(self.remove(child_h).unwrap());
// update child min expiry back up to the root
let outdated_expiry = removed_leaf.expiry();
stack.pop(); // the final parent has been replaced by the remaining leaf
self.update_parent_earliest_expiry(&stack, outdated_expiry, new_expiry);
Some(removed_leaf)
}
pub fn remove(&mut self, key: NodeHandle) -> Option<AnyNode> {
let val = *self.get(key)?;
self.nodes[key as usize] = cast(FreeNode {
tag: if self.free_list_len == 0 {
NodeTag::LastFreeNode.into()
} else {
NodeTag::FreeNode.into()
},
next: self.free_list_head,
reserve: [0; 80],
});
self.free_list_len += 1;
self.free_list_head = key;
Some(val)
}
pub fn insert(&mut self, val: &AnyNode) -> Result<NodeHandle> {
match NodeTag::try_from(val.tag) {
Ok(NodeTag::InnerNode) | Ok(NodeTag::LeafNode) => (),
_ => unreachable!(),
};
if self.free_list_len == 0 {
require!(
self.bump_index < self.nodes.len() && self.bump_index < (u32::MAX as usize),
MangoError::SomeError // todo
);
self.nodes[self.bump_index] = *val;
let key = self.bump_index as u32;
self.bump_index += 1;
return Ok(key);
}
let key = self.free_list_head;
let node = &mut self.nodes[key as usize];
// TODO OPT possibly unnecessary require here - remove if we need compute
match NodeTag::try_from(node.tag) {
Ok(NodeTag::FreeNode) => assert!(self.free_list_len > 1),
Ok(NodeTag::LastFreeNode) => assert_eq!(self.free_list_len, 1),
_ => unreachable!(),
};
// TODO - test borrow requireer
self.free_list_head = cast_ref::<AnyNode, FreeNode>(node).next;
self.free_list_len -= 1;
*node = *val;
Ok(key)
}
pub fn insert_leaf(&mut self, new_leaf: &LeafNode) -> Result<(NodeHandle, Option<LeafNode>)> {
// path of InnerNode handles that lead to the new leaf
let mut stack: Vec<(NodeHandle, bool)> = vec![];
// deal with inserts into an empty tree
let mut root: NodeHandle = match self.root() {
Some(h) => h,
None => {
// create a new root if none exists
let handle = self.insert(new_leaf.as_ref())?;
self.root_node = handle;
self.leaf_count = 1;
return Ok((handle, None));
}
};
// walk down the tree until we find the insert location
loop {
// require if the new node will be a child of the root
let root_contents = *self.get(root).unwrap();
let root_key = root_contents.key().unwrap();
if root_key == new_leaf.key {
// This should never happen because key should never match
if let Some(NodeRef::Leaf(&old_root_as_leaf)) = root_contents.case() {
// clobber the existing leaf
*self.get_mut(root).unwrap() = *new_leaf.as_ref();
self.update_parent_earliest_expiry(
&stack,
old_root_as_leaf.expiry(),
new_leaf.expiry(),
);
return Ok((root, Some(old_root_as_leaf)));
}
// InnerNodes have a random child's key, so matching can happen and is fine
}
let shared_prefix_len: u32 = (root_key ^ new_leaf.key).leading_zeros();
match root_contents.case() {
None => unreachable!(),
Some(NodeRef::Inner(inner)) => {
let keep_old_root = shared_prefix_len >= inner.prefix_len;
if keep_old_root {
let (child, crit_bit) = inner.walk_down(new_leaf.key);
stack.push((root, crit_bit));
root = child;
continue;
};
}
_ => (),
};
// implies root is a Leaf or Inner where shared_prefix_len < prefix_len
// we'll replace root with a new InnerNode that has new_leaf and root as children
// change the root in place to represent the LCA of [new_leaf] and [root]
let crit_bit_mask: i128 = 1i128 << (127 - shared_prefix_len);
let new_leaf_crit_bit = (crit_bit_mask & new_leaf.key) != 0;
let old_root_crit_bit = !new_leaf_crit_bit;
let new_leaf_handle = self.insert(new_leaf.as_ref())?;
let moved_root_handle = match self.insert(&root_contents) {
Ok(h) => h,
Err(e) => {
self.remove(new_leaf_handle).unwrap();
return Err(e);
}
};
let new_root: &mut InnerNode = cast_mut(self.get_mut(root).unwrap());
*new_root = InnerNode::new(shared_prefix_len, new_leaf.key);
new_root.children[new_leaf_crit_bit as usize] = new_leaf_handle;
new_root.children[old_root_crit_bit as usize] = moved_root_handle;
let new_leaf_expiry = new_leaf.expiry();
let old_root_expiry = root_contents.earliest_expiry();
new_root.child_earliest_expiry[new_leaf_crit_bit as usize] = new_leaf_expiry;
new_root.child_earliest_expiry[old_root_crit_bit as usize] = old_root_expiry;
// walk up the stack and fix up the new min if needed
if new_leaf_expiry < old_root_expiry {
self.update_parent_earliest_expiry(&stack, old_root_expiry, new_leaf_expiry);
}
self.leaf_count += 1;
return Ok((new_leaf_handle, None));
}
}
pub fn is_full(&self) -> bool {
self.free_list_len <= 1 && self.bump_index >= self.nodes.len() - 1
}
/// When a node changes, the parents' child_earliest_expiry may need to be updated.
///
/// This function walks up the `stack` of parents and applies the change where the
/// previous child's `outdated_expiry` is replaced by `new_expiry`.
pub fn update_parent_earliest_expiry(
&mut self,
stack: &[(NodeHandle, bool)],
mut outdated_expiry: u64,
mut new_expiry: u64,
) {
// Walk from the top of the stack to the root of the tree.
// Since the stack grows by appending, we need to iterate the slice in reverse order.
for (parent_h, crit_bit) in stack.iter().rev() {
let parent = self.get_mut(*parent_h).unwrap().as_inner_mut().unwrap();
if parent.child_earliest_expiry[*crit_bit as usize] != outdated_expiry {
break;
}
outdated_expiry = parent.earliest_expiry();
parent.child_earliest_expiry[*crit_bit as usize] = new_expiry;
new_expiry = parent.earliest_expiry();
}
}
/// Returns the handle of the node with the lowest expiry timestamp, and this timestamp
pub fn find_earliest_expiry(&self) -> Option<(NodeHandle, u64)> {
let mut current: NodeHandle = match self.root() {
Some(h) => h,
None => return None,
};
loop {
let contents = *self.get(current).unwrap();
match contents.case() {
None => unreachable!(),
Some(NodeRef::Inner(inner)) => {
current = inner.children[(inner.child_earliest_expiry[0]
> inner.child_earliest_expiry[1])
as usize];
}
_ => {
return Some((current, contents.earliest_expiry()));
}
};
}
}
}