mc/review reserved on accounts (#130)

* review and extend reserved on accounts

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* revert changes to node size, stack gets smashed in rust unit tests

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* max possible

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* max

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* Fixes from review

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* header version

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* Fix from review

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* fix

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* fixes from review

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>

* fix from review

Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
microwavedcola1 2022-08-01 16:53:30 +02:00 committed by GitHub
parent e8e774a1a4
commit c516e45d08
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 144 additions and 93 deletions

1
Cargo.lock generated
View File

@ -3156,6 +3156,7 @@ dependencies = [
"async-trait",
"base64 0.13.0",
"bincode",
"borsh",
"bytemuck",
"checked_math",
"env_logger 0.9.0",

View File

@ -25,6 +25,7 @@ anchor-lang = { path = "../../anchor/lang" }
anchor-spl = { path = "../../anchor/spl" }
arrayref = "0.3.6"
bincode = "1.3.3"
borsh = { version = "0.9.3", features = ["const-generics"] }
bytemuck = "^1.7.2"
checked_math = { path = "../../lib/checked_math" }
fixed = { version = "=1.11.0", features = ["serde", "borsh"] } # todo: higher versions don't work

View File

@ -7,6 +7,8 @@ use core::fmt::Display;
pub enum MangoError {
#[msg("")]
SomeError,
#[msg("")]
NotImplementedError,
#[msg("checked math error")]
MathError,
#[msg("")]

View File

@ -96,8 +96,9 @@ pub fn perp_create_market(
base_token_decimals,
perp_market_index,
base_token_index: base_token_index_opt.ok_or(TokenIndex::MAX).unwrap(),
padding: Default::default(),
reserved: Default::default(),
padding1: Default::default(),
padding2: Default::default(),
reserved: [0; 128],
};
let mut bids = ctx.accounts.bids.load_init()?;

View File

@ -75,8 +75,9 @@ pub fn serum3_register_market(
base_token_index: base_bank.token_index,
quote_token_index: quote_bank.token_index,
bump: *ctx.bumps.get("serum_market").ok_or(MangoError::SomeError)?,
padding: Default::default(),
reserved: Default::default(),
padding1: Default::default(),
padding2: Default::default(),
reserved: [0; 128],
};
Ok(())

View File

@ -154,7 +154,8 @@ pub fn token_register(
bump: *ctx.bumps.get("bank").ok_or(MangoError::SomeError)?,
mint_decimals: ctx.accounts.mint.decimals,
bank_num: 0,
reserved: Default::default(),
padding: Default::default(),
reserved: [0; 256],
};
// TODO: ALTs are unavailable
@ -174,8 +175,9 @@ pub fn token_register(
token_index,
address_lookup_table_bank_index: alt_previous_size as u8,
address_lookup_table_oracle_index: alt_previous_size as u8 + 1,
padding: Default::default(),
reserved: Default::default(),
padding1: Default::default(),
padding2: Default::default(),
reserved: [0; 256],
};
mint_info.banks[0] = ctx.accounts.bank.key();

View File

@ -91,15 +91,15 @@ pub struct Bank {
pub mint_decimals: u8,
pub reserved: [u8; 4],
pub padding: [u8; 4],
pub bank_num: u64,
// TODO: add space for an oracle which services interest rate for the bank's mint
// interest rate tied to oracle might help reduce spreads between deposits and borrows
pub reserved: [u8; 256],
}
const_assert_eq!(
size_of::<Bank>(),
16 + 32 * 4 + 8 * 2 + 16 * 23 + 2 * 8 + 2 + 1 + 1 + 4 + 8
16 + 32 * 4 + 8 * 2 + 16 * 23 + 2 * 8 + 2 + 1 + 1 + 4 + 8 + 256
);
const_assert_eq!(size_of::<Bank>() % 8, 0);
@ -190,7 +190,8 @@ impl Bank {
token_index: existing_bank.token_index,
bump: existing_bank.bump,
mint_decimals: existing_bank.mint_decimals,
reserved: Default::default(),
padding: Default::default(),
reserved: [0; 256],
bank_num,
}
}
@ -591,7 +592,8 @@ mod tests {
indexed_position: I80F48::ZERO,
token_index: 0,
in_use_count: if is_in_use { 1 } else { 0 },
reserved: Default::default(),
padding: Default::default(),
reserved: [0; 40],
};
account.indexed_position = indexed(I80F48::from_num(start), &bank);

View File

@ -32,9 +32,10 @@ pub struct Group {
pub version: u8,
pub padding2: [u8; 5],
pub reserved: [u8; 8],
pub reserved: [u8; 256],
}
const_assert_eq!(size_of::<Group>(), 32 * 5 + 4 + 4 + 1 * 2 + 6 + 8);
const_assert_eq!(size_of::<Group>(), 32 * 5 + 4 + 4 + 1 * 2 + 6 + 256);
const_assert_eq!(size_of::<Group>() % 8, 0);
impl Group {

View File

@ -31,6 +31,7 @@ use checked_math as cm;
type BorshVecLength = u32;
const BORSH_VEC_PADDING_BYTES: usize = 4;
const BORSH_VEC_SIZE_BYTES: usize = 4;
const DEFAULT_MANGO_ACCOUNT_VERSION: u8 = 1;
#[derive(
Debug,
@ -96,8 +97,7 @@ pub struct MangoAccount {
pub account_num: u8,
pub bump: u8,
// pub info: [u8; INFO_LEN], // TODO: Info could be in a separate PDA?
pub reserved: [u8; 4],
pub padding: [u8; 4],
// Cumulative (deposits - withdraws)
// using USD prices at the time of the deposit/withdraw
@ -107,7 +107,11 @@ pub struct MangoAccount {
// TODO: unimplemented
pub net_settled: f32,
pub reserved: [u8; 256],
// dynamic
pub header_version: u8,
pub padding0: [u8; 7],
// note: padding is required for TokenPosition, etc. to be aligned
pub padding1: u32,
// Maps token_index -> deposit/borrow account for each token
@ -134,9 +138,12 @@ impl Default for MangoAccount {
is_bankrupt: 0,
account_num: 0,
bump: 0,
reserved: Default::default(),
padding: Default::default(),
net_deposits: 0.0,
net_settled: 0.0,
reserved: [0; 256],
header_version: DEFAULT_MANGO_ACCOUNT_VERSION,
padding0: Default::default(),
padding1: Default::default(),
tokens: vec![TokenPosition::default(); 3],
padding2: Default::default(),
@ -158,7 +165,8 @@ impl MangoAccount {
}
pub fn dynamic_token_vec_offset() -> usize {
BORSH_VEC_PADDING_BYTES
8 // header version + padding
+ BORSH_VEC_PADDING_BYTES
}
pub fn dynamic_serum3_vec_offset(token_count: u8) -> usize {
@ -217,11 +225,12 @@ pub struct MangoAccountFixed {
is_bankrupt: u8,
pub account_num: u8,
pub bump: u8,
pub reserved: [u8; 4],
pub padding: [u8; 4],
pub net_deposits: f32,
pub net_settled: f32,
pub reserved: [u8; 256],
}
const_assert_eq!(size_of::<MangoAccountFixed>(), 32 * 4 + 4 + 4 + 2 * 4);
const_assert_eq!(size_of::<MangoAccountFixed>(), 32 * 4 + 4 + 4 + 2 * 4 + 256);
const_assert_eq!(size_of::<MangoAccountFixed>() % 8, 0);
impl MangoAccountFixed {
@ -267,43 +276,52 @@ pub struct MangoAccountDynamicHeader {
impl DynamicHeader for MangoAccountDynamicHeader {
fn from_bytes(data: &[u8]) -> Result<Self> {
let token_count = u8::try_from(BorshVecLength::from_le_bytes(*array_ref![
data,
MangoAccount::dynamic_token_vec_offset(),
BORSH_VEC_SIZE_BYTES
]))
.unwrap();
let header_version = u8::from_le_bytes(*array_ref![data, 0, size_of::<u8>()]);
let serum3_count = u8::try_from(BorshVecLength::from_le_bytes(*array_ref![
data,
MangoAccount::dynamic_serum3_vec_offset(token_count),
BORSH_VEC_SIZE_BYTES
]))
.unwrap();
match header_version {
1 => {
let token_count = u8::try_from(BorshVecLength::from_le_bytes(*array_ref![
data,
MangoAccount::dynamic_token_vec_offset(),
BORSH_VEC_SIZE_BYTES
]))
.unwrap();
let perp_count = u8::try_from(BorshVecLength::from_le_bytes(*array_ref![
data,
MangoAccount::dynamic_perp_vec_offset(token_count, serum3_count),
BORSH_VEC_SIZE_BYTES
]))
.unwrap();
let serum3_count = u8::try_from(BorshVecLength::from_le_bytes(*array_ref![
data,
MangoAccount::dynamic_serum3_vec_offset(token_count),
BORSH_VEC_SIZE_BYTES
]))
.unwrap();
let perp_oo_count = u8::try_from(BorshVecLength::from_le_bytes(*array_ref![
data,
MangoAccount::dynamic_perp_oo_vec_offset(token_count, serum3_count, perp_count),
BORSH_VEC_SIZE_BYTES
]))
.unwrap();
let perp_count = u8::try_from(BorshVecLength::from_le_bytes(*array_ref![
data,
MangoAccount::dynamic_perp_vec_offset(token_count, serum3_count),
BORSH_VEC_SIZE_BYTES
]))
.unwrap();
Ok(Self {
token_count,
serum3_count,
perp_count,
perp_oo_count,
})
let perp_oo_count = u8::try_from(BorshVecLength::from_le_bytes(*array_ref![
data,
MangoAccount::dynamic_perp_oo_vec_offset(token_count, serum3_count, perp_count),
BORSH_VEC_SIZE_BYTES
]))
.unwrap();
Ok(Self {
token_count,
serum3_count,
perp_count,
perp_oo_count,
})
}
_ => err!(MangoError::NotImplementedError).context("unexpected header version number"),
}
}
fn initialize(_data: &mut [u8]) -> Result<()> {
fn initialize(data: &mut [u8]) -> Result<()> {
let dst: &mut [u8] = &mut data[0..1];
dst.copy_from_slice(&DEFAULT_MANGO_ACCOUNT_VERSION.to_le_bytes());
Ok(())
}
}
@ -620,7 +638,8 @@ impl<
indexed_position: I80F48::ZERO,
token_index,
in_use_count: 0,
reserved: Default::default(),
padding: Default::default(),
reserved: [0; 40],
};
}
Ok((v, raw_index, bank_index))

View File

@ -26,13 +26,15 @@ pub struct TokenPosition {
/// incremented when a market requires this position to stay alive
pub in_use_count: u8,
pub reserved: [u8; 5],
pub padding: [u8; 5],
pub reserved: [u8; 40],
}
unsafe impl bytemuck::Pod for TokenPosition {}
unsafe impl bytemuck::Zeroable for TokenPosition {}
const_assert_eq!(size_of::<TokenPosition>(), 24);
const_assert_eq!(size_of::<TokenPosition>(), 24 + 40);
const_assert_eq!(size_of::<TokenPosition>() % 8, 0);
impl Default for TokenPosition {
@ -41,7 +43,8 @@ impl Default for TokenPosition {
indexed_position: I80F48::ZERO,
token_index: TokenIndex::MAX,
in_use_count: 0,
reserved: Default::default(),
padding: Default::default(),
reserved: [0; 40],
}
}
}
@ -98,9 +101,11 @@ pub struct Serum3Orders {
pub base_token_index: TokenIndex,
pub quote_token_index: TokenIndex,
pub reserved: [u8; 2],
pub padding: [u8; 2],
pub reserved: [u8; 64],
}
const_assert_eq!(size_of::<Serum3Orders>(), 32 + 8 * 2 + 2 * 3 + 2); // 56
const_assert_eq!(size_of::<Serum3Orders>(), 32 + 8 * 2 + 2 * 3 + 2 + 64);
const_assert_eq!(size_of::<Serum3Orders>() % 8, 0);
unsafe impl bytemuck::Pod for Serum3Orders {}
@ -123,7 +128,8 @@ impl Default for Serum3Orders {
market_index: Serum3MarketIndex::MAX,
base_token_index: TokenIndex::MAX,
quote_token_index: TokenIndex::MAX,
reserved: Default::default(),
reserved: [0; 64],
padding: Default::default(),
previous_native_coin_reserved: 0,
previous_native_pc_reserved: 0,
}
@ -134,7 +140,7 @@ impl Default for Serum3Orders {
#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct PerpPositions {
pub market_index: PerpMarketIndex,
pub reserved: [u8; 6],
pub padding: [u8; 6],
/// Active position size, measured in base lots
pub base_position_lots: i64,
@ -157,6 +163,8 @@ pub struct PerpPositions {
/// Amount that's on EventQueue waiting to be processed
pub taker_base_lots: i64,
pub taker_quote_lots: i64,
pub reserved: [u8; 64],
}
impl std::fmt::Debug for PerpPositions {
@ -172,7 +180,7 @@ impl std::fmt::Debug for PerpPositions {
.finish()
}
}
const_assert_eq!(size_of::<PerpPositions>(), 8 + 8 * 5 + 3 * 16); // 96
const_assert_eq!(size_of::<PerpPositions>(), 8 + 8 * 5 + 3 * 16 + 64);
const_assert_eq!(size_of::<PerpPositions>() % 8, 0);
unsafe impl bytemuck::Pod for PerpPositions {}
@ -188,9 +196,10 @@ impl Default for PerpPositions {
asks_base_lots: 0,
taker_base_lots: 0,
taker_quote_lots: 0,
reserved: Default::default(),
reserved: [0; 64],
long_settled_funding: I80F48::ZERO,
short_settled_funding: I80F48::ZERO,
padding: Default::default(),
}
}
}
@ -254,22 +263,24 @@ impl PerpPositions {
#[derive(AnchorSerialize, AnchorDeserialize, Debug)]
pub struct PerpOpenOrders {
pub order_side: Side, // TODO: storing enums isn't POD
pub reserved1: [u8; 1],
pub padding1: [u8; 1],
pub order_market: PerpMarketIndex,
pub reserved2: [u8; 4],
pub padding2: [u8; 4],
pub client_order_id: u64,
pub order_id: i128,
pub reserved: [u8; 64],
}
impl Default for PerpOpenOrders {
fn default() -> Self {
Self {
order_side: Side::Bid,
reserved1: Default::default(),
padding1: Default::default(),
order_market: FREE_ORDER_SLOT,
reserved2: Default::default(),
padding2: Default::default(),
client_order_id: 0,
order_id: 0,
reserved: [0; 64],
}
}
}
@ -277,7 +288,7 @@ impl Default for PerpOpenOrders {
unsafe impl bytemuck::Pod for PerpOpenOrders {}
unsafe impl bytemuck::Zeroable for PerpOpenOrders {}
const_assert_eq!(size_of::<PerpOpenOrders>(), 1 + 1 + 2 + 4 + 8 + 16);
const_assert_eq!(size_of::<PerpOpenOrders>(), 1 + 1 + 2 + 4 + 8 + 16 + 64);
const_assert_eq!(size_of::<PerpOpenOrders>() % 8, 0);
#[macro_export]

View File

@ -21,7 +21,7 @@ pub struct MintInfo {
// ABI: Clients rely on this being at offset 40
pub token_index: TokenIndex,
pub padding: [u8; 6],
pub padding1: [u8; 6],
pub mint: Pubkey,
pub banks: [Pubkey; MAX_BANKS],
pub vaults: [Pubkey; MAX_BANKS],
@ -32,11 +32,13 @@ pub struct MintInfo {
pub address_lookup_table_bank_index: u8,
pub address_lookup_table_oracle_index: u8,
pub reserved: [u8; 6],
pub padding2: [u8; 6],
pub reserved: [u8; 256],
}
const_assert_eq!(
size_of::<MintInfo>(),
MAX_BANKS * 2 * 32 + 4 * 32 + 2 + 6 + 2 + 6
MAX_BANKS * 2 * 32 + 4 * 32 + 2 + 6 + 2 + 6 + 256
);
const_assert_eq!(size_of::<MintInfo>() % 8, 0);

View File

@ -78,9 +78,9 @@ pub struct StubOracle {
pub mint: Pubkey,
pub price: I80F48,
pub last_updated: i64,
pub reserved: [u8; 8],
pub reserved: [u8; 128],
}
const_assert_eq!(size_of::<StubOracle>(), 32 + 32 + 16 + 8 + 8);
const_assert_eq!(size_of::<StubOracle>(), 32 + 32 + 16 + 8 + 128);
const_assert_eq!(size_of::<StubOracle>() % 8, 0);
pub fn determine_oracle_type(acc_info: &impl KeyedAccountReader) -> Result<OracleType> {

View File

@ -45,10 +45,11 @@ pub struct BookSide {
pub root_node: NodeHandle,
pub leaf_count: u32,
pub nodes: [AnyNode; MAX_BOOK_NODES],
pub reserved: [u8; 256],
}
const_assert_eq!(
std::mem::size_of::<BookSide>(),
1 + 3 + 4 * 2 + 4 + 4 + 4 + 88 * 1024
1 + 3 + 4 * 2 + 4 + 4 + 4 + 96 * 1024 + 256 // 98584
);
const_assert_eq!(std::mem::size_of::<BookSide>() % 8, 0);
@ -262,7 +263,7 @@ impl BookSide {
NodeTag::FreeNode.into()
},
next: self.free_list_head,
reserve: [0; 80],
reserved: [0; 88],
});
self.free_list_len += 1;
@ -458,6 +459,7 @@ mod tests {
root_node: 0,
leaf_count: 0,
nodes: [AnyNode::zeroed(); MAX_BOOK_NODES],
reserved: [0; 256],
}
}

View File

@ -32,6 +32,7 @@ mod tests {
root_node: 0,
leaf_count: 0,
nodes: [AnyNode::zeroed(); MAX_BOOK_NODES],
reserved: [0; 256],
}
}

View File

@ -9,7 +9,7 @@ use static_assertions::const_assert_eq;
use super::order_type::OrderType;
pub type NodeHandle = u32;
const NODE_SIZE: usize = 88;
const NODE_SIZE: usize = 96;
#[derive(IntoPrimitive, TryFromPrimitive)]
#[repr(u32)]
@ -46,7 +46,7 @@ pub struct InnerNode {
/// iterate through the whole bookside.
pub child_earliest_expiry: [u64; 2],
pub reserve: [u8; NODE_SIZE - 48],
pub reserved: [u8; NODE_SIZE - 48],
}
impl InnerNode {
@ -57,7 +57,7 @@ impl InnerNode {
key,
children: [0; 2],
child_earliest_expiry: [u64::MAX; 2],
reserve: [0; NODE_SIZE - 48],
reserved: [0; NODE_SIZE - 48],
}
}
@ -98,7 +98,7 @@ pub struct LeafNode {
// The time the order was placed
pub timestamp: u64,
pub reserve: [u8; NODE_SIZE - 81],
pub reserved: [u8; NODE_SIZE - 81],
}
#[inline(always)]
@ -128,7 +128,7 @@ impl LeafNode {
quantity,
client_order_id,
timestamp,
reserve: [0; NODE_SIZE - 81],
reserved: [0; NODE_SIZE - 81],
}
}
@ -158,14 +158,14 @@ impl LeafNode {
pub struct FreeNode {
pub(crate) tag: u32,
pub(crate) next: NodeHandle,
pub(crate) reserve: [u8; NODE_SIZE - 8],
pub(crate) reserved: [u8; NODE_SIZE - 8],
}
#[zero_copy]
#[derive(Pod)]
pub struct AnyNode {
pub tag: u32,
pub data: [u8; 84], // note: anchor can't parse the struct for IDL when it includes non numbers, NODE_SIZE == 88, 84 == 88 - 4
pub data: [u8; 92], // note: anchor can't parse the struct for IDL when it includes non numbers, NODE_SIZE == 96, 92 == 96 - 4
}
const_assert_eq!(size_of::<AnyNode>(), NODE_SIZE);

View File

@ -8,7 +8,7 @@ use std::mem::size_of;
use super::Side;
pub const MAX_NUM_EVENTS: u32 = 512;
pub const MAX_NUM_EVENTS: u32 = 488;
pub trait QueueHeader: bytemuck::Pod {
type Item: bytemuck::Pod + Copy;
@ -153,15 +153,15 @@ impl QueueHeader for EventQueueHeader {
}
}
const_assert_eq!(std::mem::size_of::<EventQueue>(), 4 * 2 + 8 + 512 * 200);
const_assert_eq!(std::mem::size_of::<EventQueue>(), 4 * 2 + 8 + 488 * 208);
const_assert_eq!(std::mem::size_of::<EventQueue>() % 8, 0);
const EVENT_SIZE: usize = 200;
const EVENT_SIZE: usize = 208;
#[zero_copy]
#[derive(Debug, Pod)]
pub struct AnyEvent {
pub event_type: u8,
pub padding: [u8; 199], // note: anchor can't parse the struct for IDL when it includes non numbers, EVENT_SIZE == 200, 199 == 200 - 1
pub padding: [u8; 207], // note: anchor can't parse the struct for IDL when it includes non numbers, EVENT_SIZE == 208, 207 == 208 - 1
}
const_assert_eq!(size_of::<AnyEvent>(), EVENT_SIZE);
@ -201,7 +201,7 @@ pub struct FillEvent {
pub price: i64,
pub quantity: i64, // number of quote lots
pub reserved: [u8; 8],
pub reserved: [u8; 16],
}
const_assert_eq!(size_of::<FillEvent>(), EVENT_SIZE);
@ -246,7 +246,7 @@ impl FillEvent {
taker_fee,
price,
quantity,
reserved: Default::default(),
reserved: [0; 16],
}
}

View File

@ -26,7 +26,7 @@ pub struct PerpMarket {
/// Lookup indices
pub perp_market_index: PerpMarketIndex,
pub padding: [u8; 4],
pub padding1: [u8; 4],
pub name: [u8; 16],
@ -86,12 +86,14 @@ pub struct PerpMarket {
pub base_token_decimals: u8,
pub reserved: [u8; 6],
pub padding2: [u8; 6],
pub reserved: [u8; 128],
}
const_assert_eq!(
size_of::<PerpMarket>(),
32 + 2 + 2 + 4 + 16 + 32 + 16 + 32 * 3 + 8 * 2 + 16 * 11 + 8 * 2 + 8 * 2 + 16 + 2 + 6
32 + 2 + 2 + 4 + 16 + 32 + 16 + 32 * 3 + 8 * 2 + 16 * 11 + 8 * 2 + 8 * 2 + 16 + 2 + 6 + 128
);
const_assert_eq!(size_of::<PerpMarket>() % 8, 0);

View File

@ -15,7 +15,7 @@ pub struct Serum3Market {
pub base_token_index: TokenIndex,
// ABI: Clients rely on this being at offset 42
pub quote_token_index: TokenIndex,
pub padding: [u8; 4],
pub padding1: [u8; 4],
pub name: [u8; 16],
pub serum_program: Pubkey,
pub serum_market_external: Pubkey,
@ -23,11 +23,14 @@ pub struct Serum3Market {
pub market_index: Serum3MarketIndex,
pub bump: u8,
pub reserved: [u8; 5],
pub padding2: [u8; 5],
pub reserved: [u8; 128],
}
const_assert_eq!(
size_of::<Serum3Market>(),
32 + 2 + 2 + 4 + 16 + 2 * 32 + 2 + 1 + 5
32 + 2 + 2 + 4 + 16 + 2 * 32 + 2 + 1 + 5 + 128
);
const_assert_eq!(size_of::<Serum3Market>() % 8, 0);