Account size: restict more, but only increases (#688)
* Account size: Don't fail on unrelated resize If the account was previously resized to larger than is allowed now, don't fail unrelated resizes. * Further reduce account size limits Out of caution and future-proofing. Can always raise again. Perp settle pnl needs 6 accounts plus 2 health account lists that could be nearly fully disjoint.
This commit is contained in:
parent
b7a0f9bdad
commit
a151ebcf11
|
@ -212,8 +212,8 @@ impl MangoClient {
|
|||
account_num,
|
||||
name: mango_account_name.to_owned(),
|
||||
token_count: 8,
|
||||
serum3_count: 8,
|
||||
perp_count: 8,
|
||||
serum3_count: 6,
|
||||
perp_count: 3,
|
||||
perp_oo_count: 8,
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@ pub struct AccountCreate<'info> {
|
|||
seeds = [b"MangoAccount".as_ref(), group.key().as_ref(), owner.key().as_ref(), &account_num.to_le_bytes()],
|
||||
bump,
|
||||
payer = payer,
|
||||
space = MangoAccount::space(token_count, serum3_count, perp_count, perp_oo_count, 0)?,
|
||||
space = MangoAccount::space(token_count, serum3_count, perp_count, perp_oo_count, 0),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||
pub owner: Signer<'info>,
|
||||
|
@ -39,7 +39,7 @@ pub struct AccountCreateV2<'info> {
|
|||
seeds = [b"MangoAccount".as_ref(), group.key().as_ref(), owner.key().as_ref(), &account_num.to_le_bytes()],
|
||||
bump,
|
||||
payer = payer,
|
||||
space = MangoAccount::space(token_count, serum3_count, perp_count, perp_oo_count, token_conditional_swap_count)?,
|
||||
space = MangoAccount::space(token_count, serum3_count, perp_count, perp_oo_count, token_conditional_swap_count),
|
||||
)]
|
||||
pub account: AccountLoader<'info, MangoAccountFixed>,
|
||||
pub owner: Signer<'info>,
|
||||
|
|
|
@ -18,6 +18,15 @@ pub fn account_create(
|
|||
) -> Result<()> {
|
||||
let mut account = account_ai.load_full_init()?;
|
||||
|
||||
let header = MangoAccountDynamicHeader {
|
||||
token_count,
|
||||
serum3_count,
|
||||
perp_count,
|
||||
perp_oo_count,
|
||||
token_conditional_swap_count,
|
||||
};
|
||||
header.check_resize_from(&MangoAccountDynamicHeader::zero())?;
|
||||
|
||||
msg!(
|
||||
"Initialized account with header version {}",
|
||||
account.header_version()
|
||||
|
|
|
@ -17,7 +17,7 @@ pub fn account_expand(
|
|||
perp_count,
|
||||
perp_oo_count,
|
||||
token_conditional_swap_count,
|
||||
)?;
|
||||
);
|
||||
let new_rent_minimum = Rent::get()?.minimum_balance(new_space);
|
||||
|
||||
let realloc_account = ctx.accounts.account.as_ref();
|
||||
|
|
|
@ -172,21 +172,15 @@ impl MangoAccount {
|
|||
perp_count: u8,
|
||||
perp_oo_count: u8,
|
||||
token_conditional_swap_count: u8,
|
||||
) -> Result<usize> {
|
||||
require_gte!(8, token_count);
|
||||
require_gte!(8, serum3_count);
|
||||
require_gte!(4, perp_count);
|
||||
require_gte!(64, perp_oo_count);
|
||||
require_gte!(64, token_conditional_swap_count);
|
||||
|
||||
Ok(8 + size_of::<MangoAccountFixed>()
|
||||
) -> usize {
|
||||
8 + size_of::<MangoAccountFixed>()
|
||||
+ Self::dynamic_size(
|
||||
token_count,
|
||||
serum3_count,
|
||||
perp_count,
|
||||
perp_oo_count,
|
||||
token_conditional_swap_count,
|
||||
))
|
||||
)
|
||||
}
|
||||
|
||||
pub fn dynamic_token_vec_offset() -> usize {
|
||||
|
@ -530,6 +524,65 @@ impl MangoAccountDynamicHeader {
|
|||
pub fn token_conditional_swap_count(&self) -> usize {
|
||||
self.token_conditional_swap_count.into()
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
Self {
|
||||
token_count: 0,
|
||||
serum3_count: 0,
|
||||
perp_count: 0,
|
||||
perp_oo_count: 0,
|
||||
token_conditional_swap_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn expected_health_accounts(&self) -> usize {
|
||||
self.token_count() * 2 + self.serum3_count() + self.perp_count() * 2
|
||||
}
|
||||
|
||||
/// Error if this header isn't a valid resize from `prev`
|
||||
///
|
||||
/// - Check that dynamic fields can only increase in size
|
||||
/// - Check that if something increases, it is bounded by the limits
|
||||
/// - If a field doesn't change, don't error if it exceeds the limits
|
||||
/// (might have been expanded earlier when it was valid to do)
|
||||
/// - Check that the total health accounts stay limited
|
||||
pub fn check_resize_from(&self, prev: &Self) -> Result<()> {
|
||||
require_gte!(self.token_count, prev.token_count);
|
||||
if self.token_count > prev.token_count {
|
||||
require_gte!(8, self.token_count);
|
||||
}
|
||||
|
||||
require_gte!(self.serum3_count, prev.serum3_count);
|
||||
if self.serum3_count > prev.serum3_count {
|
||||
require_gte!(6, self.serum3_count);
|
||||
}
|
||||
|
||||
require_gte!(self.perp_count, prev.perp_count);
|
||||
if self.perp_count > prev.perp_count {
|
||||
require_gte!(3, self.perp_count);
|
||||
}
|
||||
|
||||
require_gte!(self.perp_oo_count, prev.perp_oo_count);
|
||||
if self.perp_oo_count > prev.perp_oo_count {
|
||||
require_gte!(64, self.perp_oo_count);
|
||||
}
|
||||
|
||||
require_gte!(
|
||||
self.token_conditional_swap_count,
|
||||
prev.token_conditional_swap_count
|
||||
);
|
||||
if self.token_conditional_swap_count > prev.token_conditional_swap_count {
|
||||
require_gte!(64, self.token_conditional_swap_count);
|
||||
}
|
||||
|
||||
let new_health_accounts = self.expected_health_accounts();
|
||||
let prev_health_accounts = prev.expected_health_accounts();
|
||||
if new_health_accounts > prev_health_accounts {
|
||||
require_gte!(28, new_health_accounts);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Fully owned MangoAccount, useful for tests
|
||||
|
@ -1323,16 +1376,6 @@ impl<
|
|||
new_perp_oo_count: u8,
|
||||
new_token_conditional_swap_count: u8,
|
||||
) -> Result<()> {
|
||||
require_gte!(new_token_count, self.header().token_count);
|
||||
require_gte!(new_serum3_count, self.header().serum3_count);
|
||||
require_gte!(new_perp_count, self.header().perp_count);
|
||||
require_gte!(new_perp_oo_count, self.header().perp_oo_count);
|
||||
require_gte!(
|
||||
new_token_conditional_swap_count,
|
||||
self.header().token_conditional_swap_count
|
||||
);
|
||||
|
||||
// create a temp copy to compute new starting offsets
|
||||
let new_header = MangoAccountDynamicHeader {
|
||||
token_count: new_token_count,
|
||||
serum3_count: new_serum3_count,
|
||||
|
@ -1341,6 +1384,9 @@ impl<
|
|||
token_conditional_swap_count: new_token_conditional_swap_count,
|
||||
};
|
||||
let old_header = self.header().clone();
|
||||
|
||||
new_header.check_resize_from(&old_header)?;
|
||||
|
||||
let dynamic = self.dynamic_mut();
|
||||
|
||||
// expand dynamic components by first moving existing positions, and then setting new ones to defaults
|
||||
|
@ -1506,8 +1552,7 @@ mod tests {
|
|||
account.perps.len() as u8,
|
||||
account.perp_open_orders.len() as u8,
|
||||
tcs_length,
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
bytes.extend(vec![0u8; expected_space - bytes.len()]);
|
||||
|
||||
// Set the length of these dynamic parts
|
||||
|
@ -1557,7 +1602,7 @@ mod tests {
|
|||
};
|
||||
assert_eq!(
|
||||
8 + account_bytes_with_tcs.len(),
|
||||
MangoAccount::space(8, 8, 4, 8, 0).unwrap()
|
||||
MangoAccount::space(8, 8, 4, 8, 0)
|
||||
);
|
||||
|
||||
let account2 = MangoAccountValue::from_bytes(&account_bytes_without_tcs).unwrap();
|
||||
|
|
|
@ -34,7 +34,7 @@ async fn test_basic() -> Result<(), TransportError> {
|
|||
AccountCreateInstruction {
|
||||
account_num: 0,
|
||||
token_count: 6,
|
||||
serum3_count: 7,
|
||||
serum3_count: 5,
|
||||
perp_count: 0,
|
||||
perp_oo_count: 0,
|
||||
token_conditional_swap_count: 0,
|
||||
|
@ -52,7 +52,7 @@ async fn test_basic() -> Result<(), TransportError> {
|
|||
account_data.tokens.iter().filter(|t| t.is_active()).count(),
|
||||
0
|
||||
);
|
||||
assert_eq!(account_data.serum3.len(), 7);
|
||||
assert_eq!(account_data.serum3.len(), 5);
|
||||
assert_eq!(
|
||||
account_data.serum3.iter().filter(|s| s.is_active()).count(),
|
||||
0
|
||||
|
@ -66,8 +66,8 @@ async fn test_basic() -> Result<(), TransportError> {
|
|||
AccountExpandInstruction {
|
||||
account_num: 0,
|
||||
token_count: 8,
|
||||
serum3_count: 8,
|
||||
perp_count: 4,
|
||||
serum3_count: 6,
|
||||
perp_count: 3,
|
||||
perp_oo_count: 8,
|
||||
token_conditional_swap_count: 4,
|
||||
group,
|
||||
|
@ -85,13 +85,13 @@ async fn test_basic() -> Result<(), TransportError> {
|
|||
account_data.tokens.iter().filter(|t| t.is_active()).count(),
|
||||
0
|
||||
);
|
||||
assert_eq!(account_data.serum3.len(), 8);
|
||||
assert_eq!(account_data.serum3.len(), 6);
|
||||
assert_eq!(
|
||||
account_data.serum3.iter().filter(|s| s.is_active()).count(),
|
||||
0
|
||||
);
|
||||
|
||||
assert_eq!(account_data.perps.len(), 4);
|
||||
assert_eq!(account_data.perps.len(), 3);
|
||||
assert_eq!(account_data.perp_open_orders.len(), 8);
|
||||
|
||||
//
|
||||
|
|
|
@ -44,7 +44,7 @@ async fn test_health_compute_serum() -> Result<(), TransportError> {
|
|||
let admin = TestKeypair::new();
|
||||
let owner = context.users[0].key;
|
||||
let payer = context.users[1].key;
|
||||
let mints = &context.mints[0..8];
|
||||
let mints = &context.mints[0..7];
|
||||
let payer_mint_accounts = &context.users[1].token_accounts[0..mints.len()];
|
||||
|
||||
//
|
||||
|
@ -161,7 +161,7 @@ async fn test_health_compute_perp() -> Result<(), TransportError> {
|
|||
let admin = TestKeypair::new();
|
||||
let owner = context.users[0].key;
|
||||
let payer = context.users[1].key;
|
||||
let mints = &context.mints[0..5];
|
||||
let mints = &context.mints[0..4];
|
||||
let payer_mint_accounts = &context.users[1].token_accounts[0..mints.len()];
|
||||
|
||||
//
|
||||
|
|
|
@ -111,8 +111,8 @@ async fn test_token_conditional_swap() -> Result<(), TransportError> {
|
|||
AccountExpandInstruction {
|
||||
account_num: 0,
|
||||
token_count: 8,
|
||||
serum3_count: 8,
|
||||
perp_count: 4,
|
||||
serum3_count: 6,
|
||||
perp_count: 3,
|
||||
perp_oo_count: 16,
|
||||
token_conditional_swap_count: 2,
|
||||
group,
|
||||
|
|
|
@ -1824,8 +1824,8 @@ impl Default for AccountCreateInstruction {
|
|||
AccountCreateInstruction {
|
||||
account_num: 0,
|
||||
token_count: 8,
|
||||
serum3_count: 8,
|
||||
perp_count: 4,
|
||||
serum3_count: 6,
|
||||
perp_count: 3,
|
||||
perp_oo_count: 16,
|
||||
token_conditional_swap_count: 1,
|
||||
group: Default::default(),
|
||||
|
|
|
@ -739,8 +739,8 @@ export class MangoClient {
|
|||
.accountCreate(
|
||||
accountNumber ?? 0,
|
||||
tokenCount ?? 8,
|
||||
serum3Count ?? 8,
|
||||
perpCount ?? 4,
|
||||
serum3Count ?? 6,
|
||||
perpCount ?? 3,
|
||||
perpOoCount ?? 32,
|
||||
name ?? '',
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue