Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

┌─ 1 (root, init)
│ #execTerminator ( terminator ( ... kind: terminatorKindCall ( ... func: operandC
│ span: 0
│ (672 steps)
└─ 3 (stuck, leaf)
#setUpCalleeData ( monoItemFn ( ... name: symbol ( "** UNKNOWN FUNCTION **" ) ,
span: 117


┌─ 2 (root, leaf, target, terminal)
│ #EndProgram ~> .K


216 changes: 216 additions & 0 deletions kmir/src/tests/integration/data/prove-rs/spl_token_domain_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
use std::cell::RefCell;
use std::convert::TryInto;
use std::rc::Rc;

fn main() {
let base_account = Account::default();
let acc = AccountInfo::from_account(base_account.clone());
let mint = acc.clone();
let rent = acc.clone();
test_spltoken_domain_data(&acc, &mint, &rent);
}

#[derive(Clone)]
struct AccountInfo {
key: Pubkey,
lamports: Rc<RefCell<u64>>,
data: Rc<RefCell<Vec<u8>>>,
owner: Pubkey,
rent_epoch: u64,
is_signer: bool,
is_writable: bool,
executable: bool,
}

impl AccountInfo {
fn from_account(account: Account) -> Self {
let mut data = vec![0u8; Account::LEN];
Account::pack(account, &mut data[..]).unwrap();
Self {
key: Pubkey::new([0; 32]),
lamports: Rc::new(RefCell::new(0)),
data: Rc::new(RefCell::new(data)),
owner: Pubkey::new([1; 32]),
rent_epoch: 0,
is_signer: false,
is_writable: true,
executable: false,
}
}
}

fn test_spltoken_domain_data(acc: &AccountInfo, _mint: &AccountInfo, _rent: &AccountInfo) {
cheatcode_is_spl_account(acc);

let mut account = get_account(acc);

account.is_native = COption::Some(0);
assert!(account.is_native());

Account::pack(account, &mut acc.data.borrow_mut()).unwrap();

let unpacked = get_account(acc);
assert!(unpacked.is_native());
}

fn get_account(acc: &AccountInfo) -> Account {
Account::unpack_unchecked(&acc.data.borrow()).unwrap()
}

#[inline(never)]
fn cheatcode_is_spl_account(_: &AccountInfo) {}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct Pubkey([u8; 32]);

impl Pubkey {
fn new(bytes: [u8; 32]) -> Self {
Self(bytes)
}

fn as_ref(&self) -> &[u8; 32] {
&self.0
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum ProgramError {
InvalidAccountData,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum AccountState {
Uninitialized = 0,
Initialized = 1,
Frozen = 2,
}

#[derive(Clone, Debug)]
struct Account {
mint: Pubkey,
owner: Pubkey,
amount: u64,
delegate: COption<Pubkey>,
state: AccountState,
is_native: COption<u64>,
delegated_amount: u64,
close_authority: COption<Pubkey>,
}

impl Default for Account {
fn default() -> Self {
Self {
mint: Pubkey::new([2; 32]),
owner: Pubkey::new([3; 32]),
amount: 0,
delegate: COption::None,
state: AccountState::Uninitialized,
is_native: COption::None,
delegated_amount: 0,
close_authority: COption::None,
}
}
}

impl Account {
const LEN: usize = 165;

fn is_native(&self) -> bool {
matches!(self.is_native, COption::Some(_))
}

fn unpack_unchecked(data: &[u8]) -> Result<Self, ProgramError> {
if data.len() < Self::LEN {
return Err(ProgramError::InvalidAccountData);
}
let mint = Pubkey::new(data[0..32].try_into().unwrap());
let owner = Pubkey::new(data[32..64].try_into().unwrap());
let amount = u64::from_le_bytes(data[64..72].try_into().unwrap());
let delegate = decode_coption_key(&data[72..108])?;
let state = match data[108] {
0 => AccountState::Uninitialized,
1 => AccountState::Initialized,
2 => AccountState::Frozen,
_ => return Err(ProgramError::InvalidAccountData),
};
let is_native = decode_coption_u64(&data[109..121])?;
let delegated_amount = u64::from_le_bytes(data[121..129].try_into().unwrap());
let close_authority = decode_coption_key(&data[129..165])?;

Ok(Self {
mint,
owner,
amount,
delegate,
state,
is_native,
delegated_amount,
close_authority,
})
}

fn pack(account: Account, dst: &mut [u8]) -> Result<(), ProgramError> {
if dst.len() < Self::LEN {
return Err(ProgramError::InvalidAccountData);
}
dst[0..32].copy_from_slice(account.mint.as_ref());
dst[32..64].copy_from_slice(account.owner.as_ref());
dst[64..72].copy_from_slice(&account.amount.to_le_bytes());
encode_coption_key(&account.delegate, &mut dst[72..108]);
dst[108] = account.state as u8;
encode_coption_u64(&account.is_native, &mut dst[109..121]);
dst[121..129].copy_from_slice(&account.delegated_amount.to_le_bytes());
encode_coption_key(&account.close_authority, &mut dst[129..165]);
Ok(())
}
}

#[derive(Clone, Debug)]
enum COption<T> {
None,
Some(T),
}

fn decode_coption_key(bytes: &[u8]) -> Result<COption<Pubkey>, ProgramError> {
let tag = &bytes[0..4];
match tag {
[0, 0, 0, 0] => Ok(COption::None),
[1, 0, 0, 0] => Ok(COption::Some(Pubkey::new(bytes[4..36].try_into().unwrap()))),
_ => Err(ProgramError::InvalidAccountData),
}
}

fn decode_coption_u64(bytes: &[u8]) -> Result<COption<u64>, ProgramError> {
let tag = &bytes[0..4];
match tag {
[0, 0, 0, 0] => Ok(COption::None),
[1, 0, 0, 0] => Ok(COption::Some(u64::from_le_bytes(bytes[4..12].try_into().unwrap()))),
_ => Err(ProgramError::InvalidAccountData),
}
}

fn encode_coption_key(src: &COption<Pubkey>, dst: &mut [u8]) {
match src {
COption::None => {
dst[0..4].copy_from_slice(&[0; 4]);
dst[4..36].fill(0);
}
COption::Some(key) => {
dst[0..4].copy_from_slice(&[1, 0, 0, 0]);
dst[4..36].copy_from_slice(key.as_ref());
}
}
}

fn encode_coption_u64(src: &COption<u64>, dst: &mut [u8]) {
match src {
COption::None => {
dst[0..4].copy_from_slice(&[0; 4]);
dst[4..12].fill(0);
}
COption::Some(amount) => {
dst[0..4].copy_from_slice(&[1, 0, 0, 0]);
dst[4..12].copy_from_slice(&amount.to_le_bytes());
}
}
}
2 changes: 2 additions & 0 deletions kmir/src/tests/integration/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
'assume-cheatcode': ['check_assume'],
'assume-cheatcode-conflict-fail': ['check_assume_conflict'],
'transmute-bytes': ['bytes_to_u64', 'u64_to_bytes'],
'spl_token_domain_data': ['main'],
}
PROVE_RS_SHOW_SPECS = [
'local-raw-fail',
Expand All @@ -53,6 +54,7 @@
'niche-enum',
'assume-cheatcode-conflict-fail',
'raw-ptr-cast-fail',
'spl_token_domain_data',
]


Expand Down
Loading