tests: Check mango account backwards compatibility (#878)
This commit is contained in:
parent
e57dcdc2a9
commit
4f5ec41d7a
Binary file not shown.
|
@ -86,7 +86,7 @@ impl MangoAccountPdaSeeds {
|
||||||
// When not reading via idl, MangoAccount binary data is backwards compatible: when ignoring trailing bytes,
|
// When not reading via idl, MangoAccount binary data is backwards compatible: when ignoring trailing bytes,
|
||||||
// a v2 account can be read as a v1 account and a v3 account can be read as v1 or v2 etc.
|
// a v2 account can be read as a v1 account and a v3 account can be read as v1 or v2 etc.
|
||||||
#[account]
|
#[account]
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative, PartialEq)]
|
||||||
#[derivative(Debug)]
|
#[derivative(Debug)]
|
||||||
pub struct MangoAccount {
|
pub struct MangoAccount {
|
||||||
// fixed
|
// fixed
|
||||||
|
@ -747,6 +747,12 @@ impl<
|
||||||
self.dynamic.deref_or_borrow()
|
self.dynamic.deref_or_borrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn dynamic_reserved_bytes(&self) -> &[u8] {
|
||||||
|
let reserved_offset = self.header().reserved_bytes_offset();
|
||||||
|
&self.dynamic()[reserved_offset..reserved_offset + DYNAMIC_RESERVED_BYTES]
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns
|
/// Returns
|
||||||
/// - the position
|
/// - the position
|
||||||
/// - the raw index into the token positions list (for use with get_raw/deactivate)
|
/// - the raw index into the token positions list (for use with get_raw/deactivate)
|
||||||
|
@ -1876,6 +1882,7 @@ impl<'a, 'info: 'a> MangoAccountLoader<'a> for &'a AccountLoader<'info, MangoAcc
|
||||||
mod tests {
|
mod tests {
|
||||||
use bytemuck::Zeroable;
|
use bytemuck::Zeroable;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::state::PostOrderType;
|
use crate::state::PostOrderType;
|
||||||
|
|
||||||
|
@ -2402,12 +2409,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let reserved_offset = account.header.reserved_bytes_offset();
|
assert!(account.dynamic_reserved_bytes().iter().all(|&v| v == 0));
|
||||||
assert!(
|
|
||||||
account.dynamic[reserved_offset..reserved_offset + DYNAMIC_RESERVED_BYTES]
|
|
||||||
.iter()
|
|
||||||
.all(|&v| v == 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -2862,4 +2864,88 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(to_be_closed_account_opt.unwrap().market_index, 3)
|
assert_eq!(to_be_closed_account_opt.unwrap().market_index, 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attempts reading old mango account data with borsh and with zerocopy
|
||||||
|
#[test]
|
||||||
|
fn test_mango_account_backwards_compatibility() -> Result<()> {
|
||||||
|
use solana_program_test::{find_file, read_file};
|
||||||
|
|
||||||
|
let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
d.push("resources/test");
|
||||||
|
|
||||||
|
// Grab live accounts with
|
||||||
|
// solana account CZGf1qbYPaSoabuA1EmdN8W5UHvH5CeXcNZ7RTx65aVQ --output-file programs/mango-v4/resources/test/mangoaccount-v0.21.3.bin
|
||||||
|
let fixtures = vec!["mangoaccount-v0.21.3"];
|
||||||
|
|
||||||
|
for fixture in fixtures {
|
||||||
|
let filename = format!("resources/test/{}.bin", fixture);
|
||||||
|
let account_bytes = read_file(find_file(&filename).unwrap());
|
||||||
|
|
||||||
|
// Read with borsh
|
||||||
|
let mut account_bytes_slice: &[u8] = &account_bytes;
|
||||||
|
let borsh_account = MangoAccount::try_deserialize(&mut account_bytes_slice)?;
|
||||||
|
|
||||||
|
// Read with zerocopy
|
||||||
|
let zerocopy_reader = MangoAccountValue::from_bytes(&account_bytes[8..])?;
|
||||||
|
let fixed = &zerocopy_reader.fixed;
|
||||||
|
let zerocopy_account = MangoAccount {
|
||||||
|
group: fixed.group,
|
||||||
|
owner: fixed.owner,
|
||||||
|
name: fixed.name,
|
||||||
|
delegate: fixed.delegate,
|
||||||
|
account_num: fixed.account_num,
|
||||||
|
being_liquidated: fixed.being_liquidated,
|
||||||
|
in_health_region: fixed.in_health_region,
|
||||||
|
bump: fixed.bump,
|
||||||
|
padding: Default::default(),
|
||||||
|
net_deposits: fixed.net_deposits,
|
||||||
|
perp_spot_transfers: fixed.perp_spot_transfers,
|
||||||
|
health_region_begin_init_health: fixed.health_region_begin_init_health,
|
||||||
|
frozen_until: fixed.frozen_until,
|
||||||
|
buyback_fees_accrued_current: fixed.buyback_fees_accrued_current,
|
||||||
|
buyback_fees_accrued_previous: fixed.buyback_fees_accrued_previous,
|
||||||
|
buyback_fees_expiry_timestamp: fixed.buyback_fees_expiry_timestamp,
|
||||||
|
next_token_conditional_swap_id: fixed.next_token_conditional_swap_id,
|
||||||
|
temporary_delegate: fixed.temporary_delegate,
|
||||||
|
temporary_delegate_expiry: fixed.temporary_delegate_expiry,
|
||||||
|
last_collateral_fee_charge: fixed.last_collateral_fee_charge,
|
||||||
|
reserved: [0u8; 152],
|
||||||
|
|
||||||
|
header_version: *zerocopy_reader.header_version(),
|
||||||
|
padding3: Default::default(),
|
||||||
|
|
||||||
|
padding4: Default::default(),
|
||||||
|
tokens: zerocopy_reader.all_token_positions().cloned().collect_vec(),
|
||||||
|
|
||||||
|
padding5: Default::default(),
|
||||||
|
serum3: zerocopy_reader.all_serum3_orders().cloned().collect_vec(),
|
||||||
|
|
||||||
|
padding6: Default::default(),
|
||||||
|
perps: zerocopy_reader.all_perp_positions().cloned().collect_vec(),
|
||||||
|
|
||||||
|
padding7: Default::default(),
|
||||||
|
perp_open_orders: zerocopy_reader.all_perp_orders().cloned().collect_vec(),
|
||||||
|
|
||||||
|
padding8: Default::default(),
|
||||||
|
token_conditional_swaps: zerocopy_reader
|
||||||
|
.all_token_conditional_swaps()
|
||||||
|
.cloned()
|
||||||
|
.collect_vec(),
|
||||||
|
|
||||||
|
reserved_dynamic: zerocopy_reader.dynamic_reserved_bytes().try_into().unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Both methods agree?
|
||||||
|
assert_eq!(borsh_account, zerocopy_account);
|
||||||
|
|
||||||
|
// Serializing and deserializing produces the same data?
|
||||||
|
let mut borsh_bytes = Vec::new();
|
||||||
|
borsh_account.try_serialize(&mut borsh_bytes)?;
|
||||||
|
let mut slice: &[u8] = &borsh_bytes;
|
||||||
|
let roundtrip_account = MangoAccount::try_deserialize(&mut slice)?;
|
||||||
|
assert_eq!(borsh_account, roundtrip_account);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::state::*;
|
||||||
pub const FREE_ORDER_SLOT: PerpMarketIndex = PerpMarketIndex::MAX;
|
pub const FREE_ORDER_SLOT: PerpMarketIndex = PerpMarketIndex::MAX;
|
||||||
|
|
||||||
#[zero_copy]
|
#[zero_copy]
|
||||||
#[derive(AnchorDeserialize, AnchorSerialize, Derivative)]
|
#[derive(AnchorDeserialize, AnchorSerialize, Derivative, PartialEq)]
|
||||||
#[derivative(Debug)]
|
#[derivative(Debug)]
|
||||||
pub struct TokenPosition {
|
pub struct TokenPosition {
|
||||||
// TODO: Why did we have deposits and borrows as two different values
|
// TODO: Why did we have deposits and borrows as two different values
|
||||||
|
@ -110,7 +110,7 @@ impl TokenPosition {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zero_copy]
|
#[zero_copy]
|
||||||
#[derive(AnchorSerialize, AnchorDeserialize, Derivative)]
|
#[derive(AnchorSerialize, AnchorDeserialize, Derivative, PartialEq)]
|
||||||
#[derivative(Debug)]
|
#[derivative(Debug)]
|
||||||
pub struct Serum3Orders {
|
pub struct Serum3Orders {
|
||||||
pub open_orders: Pubkey,
|
pub open_orders: Pubkey,
|
||||||
|
@ -203,7 +203,7 @@ impl Default for Serum3Orders {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zero_copy]
|
#[zero_copy]
|
||||||
#[derive(AnchorSerialize, AnchorDeserialize, Derivative)]
|
#[derive(AnchorSerialize, AnchorDeserialize, Derivative, PartialEq)]
|
||||||
#[derivative(Debug)]
|
#[derivative(Debug)]
|
||||||
pub struct PerpPosition {
|
pub struct PerpPosition {
|
||||||
pub market_index: PerpMarketIndex,
|
pub market_index: PerpMarketIndex,
|
||||||
|
@ -785,7 +785,7 @@ impl PerpPosition {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zero_copy]
|
#[zero_copy]
|
||||||
#[derive(AnchorSerialize, AnchorDeserialize, Derivative)]
|
#[derive(AnchorSerialize, AnchorDeserialize, Derivative, PartialEq)]
|
||||||
#[derivative(Debug)]
|
#[derivative(Debug)]
|
||||||
pub struct PerpOpenOrder {
|
pub struct PerpOpenOrder {
|
||||||
pub side_and_tree: u8, // SideAndOrderTree -- enums aren't POD
|
pub side_and_tree: u8, // SideAndOrderTree -- enums aren't POD
|
||||||
|
|
|
@ -45,7 +45,7 @@ pub enum TokenConditionalSwapType {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[zero_copy]
|
#[zero_copy]
|
||||||
#[derive(AnchorDeserialize, AnchorSerialize, Derivative)]
|
#[derive(AnchorDeserialize, AnchorSerialize, Derivative, PartialEq)]
|
||||||
#[derivative(Debug)]
|
#[derivative(Debug)]
|
||||||
pub struct TokenConditionalSwap {
|
pub struct TokenConditionalSwap {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
|
|
Loading…
Reference in New Issue