spl_token_2022/extension/
mod.rs

1//! Extensions available to token mints and accounts
2
3#[cfg(feature = "serde-traits")]
4use serde::{Deserialize, Serialize};
5use {
6    crate::{
7        error::TokenError,
8        extension::{
9            confidential_transfer::{ConfidentialTransferAccount, ConfidentialTransferMint},
10            confidential_transfer_fee::{
11                ConfidentialTransferFeeAmount, ConfidentialTransferFeeConfig,
12            },
13            cpi_guard::CpiGuard,
14            default_account_state::DefaultAccountState,
15            group_member_pointer::GroupMemberPointer,
16            group_pointer::GroupPointer,
17            immutable_owner::ImmutableOwner,
18            interest_bearing_mint::InterestBearingConfig,
19            memo_transfer::MemoTransfer,
20            metadata_pointer::MetadataPointer,
21            mint_close_authority::MintCloseAuthority,
22            non_transferable::{NonTransferable, NonTransferableAccount},
23            permanent_delegate::PermanentDelegate,
24            transfer_fee::{TransferFeeAmount, TransferFeeConfig},
25            transfer_hook::{TransferHook, TransferHookAccount},
26        },
27        pod::{PodAccount, PodMint},
28        state::{Account, Mint, Multisig, PackedSizeOf},
29    },
30    bytemuck::{Pod, Zeroable},
31    miraland_program::{
32        account_info::AccountInfo,
33        program_error::ProgramError,
34        program_pack::{IsInitialized, Pack},
35    },
36    num_enum::{IntoPrimitive, TryFromPrimitive},
37    spl_pod::{
38        bytemuck::{pod_from_bytes, pod_from_bytes_mut, pod_get_packed_len},
39        primitives::PodU16,
40    },
41    spl_token_group_interface::state::{TokenGroup, TokenGroupMember},
42    spl_type_length_value::variable_len_pack::VariableLenPack,
43    std::{
44        cmp::Ordering,
45        convert::{TryFrom, TryInto},
46        mem::size_of,
47    },
48};
49
50/// Confidential Transfer extension
51pub mod confidential_transfer;
52/// Confidential Transfer Fee extension
53pub mod confidential_transfer_fee;
54/// CPI Guard extension
55pub mod cpi_guard;
56/// Default Account State extension
57pub mod default_account_state;
58/// Group Member Pointer extension
59pub mod group_member_pointer;
60/// Group Pointer extension
61pub mod group_pointer;
62/// Immutable Owner extension
63pub mod immutable_owner;
64/// Interest-Bearing Mint extension
65pub mod interest_bearing_mint;
66/// Memo Transfer extension
67pub mod memo_transfer;
68/// Metadata Pointer extension
69pub mod metadata_pointer;
70/// Mint Close Authority extension
71pub mod mint_close_authority;
72/// Non Transferable extension
73pub mod non_transferable;
74/// Permanent Delegate extension
75pub mod permanent_delegate;
76/// Utility to reallocate token accounts
77pub mod reallocate;
78/// Token-group extension
79pub mod token_group;
80/// Token-metadata extension
81pub mod token_metadata;
82/// Transfer Fee extension
83pub mod transfer_fee;
84/// Transfer Hook extension
85pub mod transfer_hook;
86
87/// Length in TLV structure
88#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
89#[repr(transparent)]
90pub struct Length(PodU16);
91impl From<Length> for usize {
92    fn from(n: Length) -> Self {
93        Self::from(u16::from(n.0))
94    }
95}
96impl TryFrom<usize> for Length {
97    type Error = ProgramError;
98    fn try_from(n: usize) -> Result<Self, Self::Error> {
99        u16::try_from(n)
100            .map(|v| Self(PodU16::from(v)))
101            .map_err(|_| ProgramError::AccountDataTooSmall)
102    }
103}
104
105/// Helper function to get the current TlvIndices from the current spot
106fn get_tlv_indices(type_start: usize) -> TlvIndices {
107    let length_start = type_start.saturating_add(size_of::<ExtensionType>());
108    let value_start = length_start.saturating_add(pod_get_packed_len::<Length>());
109    TlvIndices {
110        type_start,
111        length_start,
112        value_start,
113    }
114}
115
116/// Helper function to tack on the size of an extension bytes if an account with
117/// extensions is exactly the size of a multisig
118const fn adjust_len_for_multisig(account_len: usize) -> usize {
119    if account_len == Multisig::LEN {
120        account_len.saturating_add(size_of::<ExtensionType>())
121    } else {
122        account_len
123    }
124}
125
126/// Helper function to calculate exactly how many bytes a value will take up,
127/// given the value's length
128const fn add_type_and_length_to_len(value_len: usize) -> usize {
129    value_len
130        .saturating_add(size_of::<ExtensionType>())
131        .saturating_add(pod_get_packed_len::<Length>())
132}
133
134/// Helper struct for returning the indices of the type, length, and value in
135/// a TLV entry
136#[derive(Debug)]
137struct TlvIndices {
138    pub type_start: usize,
139    pub length_start: usize,
140    pub value_start: usize,
141}
142fn get_extension_indices<V: Extension>(
143    tlv_data: &[u8],
144    init: bool,
145) -> Result<TlvIndices, ProgramError> {
146    let mut start_index = 0;
147    let v_account_type = V::TYPE.get_account_type();
148    while start_index < tlv_data.len() {
149        let tlv_indices = get_tlv_indices(start_index);
150        if tlv_data.len() < tlv_indices.value_start {
151            return Err(ProgramError::InvalidAccountData);
152        }
153        let extension_type =
154            ExtensionType::try_from(&tlv_data[tlv_indices.type_start..tlv_indices.length_start])?;
155        let account_type = extension_type.get_account_type();
156        if extension_type == V::TYPE {
157            // found an instance of the extension that we're initializing, return!
158            return Ok(tlv_indices);
159        // got to an empty spot, init here, or error if we're searching, since
160        // nothing is written after an Uninitialized spot
161        } else if extension_type == ExtensionType::Uninitialized {
162            if init {
163                return Ok(tlv_indices);
164            } else {
165                return Err(TokenError::ExtensionNotFound.into());
166            }
167        } else if v_account_type != account_type {
168            return Err(TokenError::ExtensionTypeMismatch.into());
169        } else {
170            let length = pod_from_bytes::<Length>(
171                &tlv_data[tlv_indices.length_start..tlv_indices.value_start],
172            )?;
173            let value_end_index = tlv_indices.value_start.saturating_add(usize::from(*length));
174            start_index = value_end_index;
175        }
176    }
177    Err(ProgramError::InvalidAccountData)
178}
179
180/// Basic information about the TLV buffer, collected from iterating through all
181/// entries
182#[derive(Debug, PartialEq)]
183struct TlvDataInfo {
184    /// The extension types written in the TLV buffer
185    extension_types: Vec<ExtensionType>,
186    /// The total number bytes allocated for all TLV entries.
187    ///
188    /// Each TLV entry's allocated bytes comprises two bytes for the `type`, two
189    /// bytes for the `length`, and `length` number of bytes for the `value`.
190    used_len: usize,
191}
192
193/// Fetches basic information about the TLV buffer by iterating through all
194/// TLV entries.
195fn get_tlv_data_info(tlv_data: &[u8]) -> Result<TlvDataInfo, ProgramError> {
196    let mut extension_types = vec![];
197    let mut start_index = 0;
198    while start_index < tlv_data.len() {
199        let tlv_indices = get_tlv_indices(start_index);
200        if tlv_data.len() < tlv_indices.length_start {
201            // There aren't enough bytes to store the next type, which means we
202            // got to the end. The last byte could be used during a realloc!
203            return Ok(TlvDataInfo {
204                extension_types,
205                used_len: tlv_indices.type_start,
206            });
207        }
208        let extension_type =
209            ExtensionType::try_from(&tlv_data[tlv_indices.type_start..tlv_indices.length_start])?;
210        if extension_type == ExtensionType::Uninitialized {
211            return Ok(TlvDataInfo {
212                extension_types,
213                used_len: tlv_indices.type_start,
214            });
215        } else {
216            if tlv_data.len() < tlv_indices.value_start {
217                // not enough bytes to store the length, malformed
218                return Err(ProgramError::InvalidAccountData);
219            }
220            extension_types.push(extension_type);
221            let length = pod_from_bytes::<Length>(
222                &tlv_data[tlv_indices.length_start..tlv_indices.value_start],
223            )?;
224
225            let value_end_index = tlv_indices.value_start.saturating_add(usize::from(*length));
226            if value_end_index > tlv_data.len() {
227                // value blows past the size of the slice, malformed
228                return Err(ProgramError::InvalidAccountData);
229            }
230            start_index = value_end_index;
231        }
232    }
233    Ok(TlvDataInfo {
234        extension_types,
235        used_len: start_index,
236    })
237}
238
239fn get_first_extension_type(tlv_data: &[u8]) -> Result<Option<ExtensionType>, ProgramError> {
240    if tlv_data.is_empty() {
241        Ok(None)
242    } else {
243        let tlv_indices = get_tlv_indices(0);
244        if tlv_data.len() <= tlv_indices.length_start {
245            return Ok(None);
246        }
247        let extension_type =
248            ExtensionType::try_from(&tlv_data[tlv_indices.type_start..tlv_indices.length_start])?;
249        if extension_type == ExtensionType::Uninitialized {
250            Ok(None)
251        } else {
252            Ok(Some(extension_type))
253        }
254    }
255}
256
257fn check_min_len_and_not_multisig(input: &[u8], minimum_len: usize) -> Result<(), ProgramError> {
258    if input.len() == Multisig::LEN || input.len() < minimum_len {
259        Err(ProgramError::InvalidAccountData)
260    } else {
261        Ok(())
262    }
263}
264
265fn check_account_type<S: BaseState>(account_type: AccountType) -> Result<(), ProgramError> {
266    if account_type != S::ACCOUNT_TYPE {
267        Err(ProgramError::InvalidAccountData)
268    } else {
269        Ok(())
270    }
271}
272
273/// Any account with extensions must be at least `Account::LEN`.  Both mints and
274/// accounts can have extensions
275/// A mint with extensions that takes it past 165 could be indiscernible from an
276/// Account with an extension, even if we add the account type. For example,
277/// let's say we have:
278///
279/// Account: 165 bytes... + [2, 0, 3, 0, 100, ....]
280///                          ^     ^       ^     ^
281///                     acct type  extension length data...
282///
283/// Mint: 82 bytes... + 83 bytes of other extension data
284///     + [2, 0, 3, 0, 100, ....]
285///      (data in extension just happens to look like this)
286///
287/// With this approach, we only start writing the TLV data after Account::LEN,
288/// which means we always know that the account type is going to be right after
289/// that. We do a special case checking for a Multisig length, because those
290/// aren't extensible under any circumstances.
291const BASE_ACCOUNT_LENGTH: usize = Account::LEN;
292/// Helper that tacks on the AccountType length, which gives the minimum for any
293/// account with extensions
294const BASE_ACCOUNT_AND_TYPE_LENGTH: usize = BASE_ACCOUNT_LENGTH + size_of::<AccountType>();
295
296fn type_and_tlv_indices<S: BaseState>(
297    rest_input: &[u8],
298) -> Result<Option<(usize, usize)>, ProgramError> {
299    if rest_input.is_empty() {
300        Ok(None)
301    } else {
302        let account_type_index = BASE_ACCOUNT_LENGTH.saturating_sub(S::SIZE_OF);
303        // check padding is all zeroes
304        let tlv_start_index = account_type_index.saturating_add(size_of::<AccountType>());
305        if rest_input.len() <= tlv_start_index {
306            return Err(ProgramError::InvalidAccountData);
307        }
308        if rest_input[..account_type_index] != vec![0; account_type_index] {
309            Err(ProgramError::InvalidAccountData)
310        } else {
311            Ok(Some((account_type_index, tlv_start_index)))
312        }
313    }
314}
315
316/// Checks a base buffer to verify if it is an Account without having to
317/// completely deserialize it
318fn is_initialized_account(input: &[u8]) -> Result<bool, ProgramError> {
319    const ACCOUNT_INITIALIZED_INDEX: usize = 108; // See state.rs#L99
320
321    if input.len() != BASE_ACCOUNT_LENGTH {
322        return Err(ProgramError::InvalidAccountData);
323    }
324    Ok(input[ACCOUNT_INITIALIZED_INDEX] != 0)
325}
326
327fn get_extension_bytes<S: BaseState, V: Extension>(tlv_data: &[u8]) -> Result<&[u8], ProgramError> {
328    if V::TYPE.get_account_type() != S::ACCOUNT_TYPE {
329        return Err(ProgramError::InvalidAccountData);
330    }
331    let TlvIndices {
332        type_start: _,
333        length_start,
334        value_start,
335    } = get_extension_indices::<V>(tlv_data, false)?;
336    // get_extension_indices has checked that tlv_data is long enough to include
337    // these indices
338    let length = pod_from_bytes::<Length>(&tlv_data[length_start..value_start])?;
339    let value_end = value_start.saturating_add(usize::from(*length));
340    if tlv_data.len() < value_end {
341        return Err(ProgramError::InvalidAccountData);
342    }
343    Ok(&tlv_data[value_start..value_end])
344}
345
346fn get_extension_bytes_mut<S: BaseState, V: Extension>(
347    tlv_data: &mut [u8],
348) -> Result<&mut [u8], ProgramError> {
349    if V::TYPE.get_account_type() != S::ACCOUNT_TYPE {
350        return Err(ProgramError::InvalidAccountData);
351    }
352    let TlvIndices {
353        type_start: _,
354        length_start,
355        value_start,
356    } = get_extension_indices::<V>(tlv_data, false)?;
357    // get_extension_indices has checked that tlv_data is long enough to include
358    // these indices
359    let length = pod_from_bytes::<Length>(&tlv_data[length_start..value_start])?;
360    let value_end = value_start.saturating_add(usize::from(*length));
361    if tlv_data.len() < value_end {
362        return Err(ProgramError::InvalidAccountData);
363    }
364    Ok(&mut tlv_data[value_start..value_end])
365}
366
367/// Calculate the new expected size if the state allocates the given number
368/// of bytes for the given extension type.
369///
370/// Provides the correct answer regardless if the extension is already present
371/// in the TLV data.
372fn try_get_new_account_len_for_extension_len<S: BaseState, V: Extension>(
373    tlv_data: &[u8],
374    new_extension_len: usize,
375) -> Result<usize, ProgramError> {
376    // get the new length used by the extension
377    let new_extension_tlv_len = add_type_and_length_to_len(new_extension_len);
378    let tlv_info = get_tlv_data_info(tlv_data)?;
379    // If we're adding an extension, then we must have at least BASE_ACCOUNT_LENGTH
380    // and account type
381    let current_len = tlv_info
382        .used_len
383        .saturating_add(BASE_ACCOUNT_AND_TYPE_LENGTH);
384    // get the current length used by the extension
385    let current_extension_len = get_extension_bytes::<S, V>(tlv_data)
386        .map(|x| add_type_and_length_to_len(x.len()))
387        .unwrap_or(0);
388    let new_len = current_len
389        .saturating_sub(current_extension_len)
390        .saturating_add(new_extension_tlv_len);
391    Ok(adjust_len_for_multisig(new_len))
392}
393
394/// Trait for base state with extension
395pub trait BaseStateWithExtensions<S: BaseState> {
396    /// Get the buffer containing all extension data
397    fn get_tlv_data(&self) -> &[u8];
398
399    /// Fetch the bytes for a TLV entry
400    fn get_extension_bytes<V: Extension>(&self) -> Result<&[u8], ProgramError> {
401        get_extension_bytes::<S, V>(self.get_tlv_data())
402    }
403
404    /// Unpack a portion of the TLV data as the desired type
405    fn get_extension<V: Extension + Pod>(&self) -> Result<&V, ProgramError> {
406        pod_from_bytes::<V>(self.get_extension_bytes::<V>()?)
407    }
408
409    /// Unpacks a portion of the TLV data as the desired variable-length type
410    fn get_variable_len_extension<V: Extension + VariableLenPack>(
411        &self,
412    ) -> Result<V, ProgramError> {
413        let data = get_extension_bytes::<S, V>(self.get_tlv_data())?;
414        V::unpack_from_slice(data)
415    }
416
417    /// Iterates through the TLV entries, returning only the types
418    fn get_extension_types(&self) -> Result<Vec<ExtensionType>, ProgramError> {
419        get_tlv_data_info(self.get_tlv_data()).map(|x| x.extension_types)
420    }
421
422    /// Get just the first extension type, useful to track mixed initializations
423    fn get_first_extension_type(&self) -> Result<Option<ExtensionType>, ProgramError> {
424        get_first_extension_type(self.get_tlv_data())
425    }
426
427    /// Get the total number of bytes used by TLV entries and the base type
428    fn try_get_account_len(&self) -> Result<usize, ProgramError> {
429        let tlv_info = get_tlv_data_info(self.get_tlv_data())?;
430        if tlv_info.extension_types.is_empty() {
431            Ok(S::SIZE_OF)
432        } else {
433            let total_len = tlv_info
434                .used_len
435                .saturating_add(BASE_ACCOUNT_AND_TYPE_LENGTH);
436            Ok(adjust_len_for_multisig(total_len))
437        }
438    }
439    /// Calculate the new expected size if the state allocates the given
440    /// fixed-length extension instance.
441    /// If the state already has the extension, the resulting account length
442    /// will be unchanged.
443    fn try_get_new_account_len<V: Extension + Pod>(&self) -> Result<usize, ProgramError> {
444        try_get_new_account_len_for_extension_len::<S, V>(
445            self.get_tlv_data(),
446            pod_get_packed_len::<V>(),
447        )
448    }
449
450    /// Calculate the new expected size if the state allocates the given
451    /// variable-length extension instance.
452    fn try_get_new_account_len_for_variable_len_extension<V: Extension + VariableLenPack>(
453        &self,
454        new_extension: &V,
455    ) -> Result<usize, ProgramError> {
456        try_get_new_account_len_for_extension_len::<S, V>(
457            self.get_tlv_data(),
458            new_extension.get_packed_len()?,
459        )
460    }
461}
462
463/// Encapsulates owned immutable base state data (mint or account) with possible
464/// extensions
465#[derive(Clone, Debug, PartialEq)]
466pub struct StateWithExtensionsOwned<S: BaseState> {
467    /// Unpacked base data
468    pub base: S,
469    /// Raw TLV data, deserialized on demand
470    tlv_data: Vec<u8>,
471}
472impl<S: BaseState + Pack> StateWithExtensionsOwned<S> {
473    /// Unpack base state, leaving the extension data as a slice
474    ///
475    /// Fails if the base state is not initialized.
476    pub fn unpack(mut input: Vec<u8>) -> Result<Self, ProgramError> {
477        check_min_len_and_not_multisig(&input, S::SIZE_OF)?;
478        let mut rest = input.split_off(S::SIZE_OF);
479        let base = S::unpack(&input)?;
480        if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::<S>(&rest)? {
481            // type_and_tlv_indices() checks that returned indexes are within range
482            let account_type = AccountType::try_from(rest[account_type_index])
483                .map_err(|_| ProgramError::InvalidAccountData)?;
484            check_account_type::<S>(account_type)?;
485            let tlv_data = rest.split_off(tlv_start_index);
486            Ok(Self { base, tlv_data })
487        } else {
488            Ok(Self {
489                base,
490                tlv_data: vec![],
491            })
492        }
493    }
494}
495
496impl<S: BaseState> BaseStateWithExtensions<S> for StateWithExtensionsOwned<S> {
497    fn get_tlv_data(&self) -> &[u8] {
498        &self.tlv_data
499    }
500}
501
502/// Encapsulates immutable base state data (mint or account) with possible
503/// extensions
504#[derive(Debug, PartialEq)]
505pub struct StateWithExtensions<'data, S: BaseState + Pack> {
506    /// Unpacked base data
507    pub base: S,
508    /// Slice of data containing all TLV data, deserialized on demand
509    tlv_data: &'data [u8],
510}
511impl<'data, S: BaseState + Pack> StateWithExtensions<'data, S> {
512    /// Unpack base state, leaving the extension data as a slice
513    ///
514    /// Fails if the base state is not initialized.
515    pub fn unpack(input: &'data [u8]) -> Result<Self, ProgramError> {
516        check_min_len_and_not_multisig(input, S::SIZE_OF)?;
517        let (base_data, rest) = input.split_at(S::SIZE_OF);
518        let base = S::unpack(base_data)?;
519        let tlv_data = unpack_tlv_data::<S>(rest)?;
520        Ok(Self { base, tlv_data })
521    }
522}
523impl<'a, S: BaseState + Pack> BaseStateWithExtensions<S> for StateWithExtensions<'a, S> {
524    fn get_tlv_data(&self) -> &[u8] {
525        self.tlv_data
526    }
527}
528
529/// Encapsulates immutable base state data (mint or account) with possible
530/// extensions, where the base state is Pod for zero-copy serde.
531#[derive(Debug, PartialEq)]
532pub struct PodStateWithExtensions<'data, S: BaseState + Pod> {
533    /// Unpacked base data
534    pub base: &'data S,
535    /// Slice of data containing all TLV data, deserialized on demand
536    tlv_data: &'data [u8],
537}
538impl<'data, S: BaseState + Pod> PodStateWithExtensions<'data, S> {
539    /// Unpack base state, leaving the extension data as a slice
540    ///
541    /// Fails if the base state is not initialized.
542    pub fn unpack(input: &'data [u8]) -> Result<Self, ProgramError> {
543        check_min_len_and_not_multisig(input, S::SIZE_OF)?;
544        let (base_data, rest) = input.split_at(S::SIZE_OF);
545        let base = pod_from_bytes::<S>(base_data)?;
546        if !base.is_initialized() {
547            Err(ProgramError::UninitializedAccount)
548        } else {
549            let tlv_data = unpack_tlv_data::<S>(rest)?;
550            Ok(Self { base, tlv_data })
551        }
552    }
553}
554impl<'a, S: BaseState + Pod> BaseStateWithExtensions<S> for PodStateWithExtensions<'a, S> {
555    fn get_tlv_data(&self) -> &[u8] {
556        self.tlv_data
557    }
558}
559
560/// Trait for mutable base state with extension
561pub trait BaseStateWithExtensionsMut<S: BaseState>: BaseStateWithExtensions<S> {
562    /// Get the underlying TLV data as mutable
563    fn get_tlv_data_mut(&mut self) -> &mut [u8];
564
565    /// Get the underlying account type as mutable
566    fn get_account_type_mut(&mut self) -> &mut [u8];
567
568    /// Unpack a portion of the TLV data as the base mutable bytes
569    fn get_extension_bytes_mut<V: Extension>(&mut self) -> Result<&mut [u8], ProgramError> {
570        get_extension_bytes_mut::<S, V>(self.get_tlv_data_mut())
571    }
572
573    /// Unpack a portion of the TLV data as the desired type that allows
574    /// modifying the type
575    fn get_extension_mut<V: Extension + Pod>(&mut self) -> Result<&mut V, ProgramError> {
576        pod_from_bytes_mut::<V>(self.get_extension_bytes_mut::<V>()?)
577    }
578
579    /// Packs a variable-length extension into its appropriate data segment.
580    /// Fails if space hasn't already been allocated for the given extension
581    fn pack_variable_len_extension<V: Extension + VariableLenPack>(
582        &mut self,
583        extension: &V,
584    ) -> Result<(), ProgramError> {
585        let data = self.get_extension_bytes_mut::<V>()?;
586        // NOTE: Do *not* use `pack`, since the length check will cause
587        // reallocations to smaller sizes to fail
588        extension.pack_into_slice(data)
589    }
590
591    /// Packs the default extension data into an open slot if not already found
592    /// in the data buffer. If extension is already found in the buffer, it
593    /// overwrites the existing extension with the default state if
594    /// `overwrite` is set. If extension found, but `overwrite` is not set,
595    /// it returns error.
596    fn init_extension<V: Extension + Pod + Default>(
597        &mut self,
598        overwrite: bool,
599    ) -> Result<&mut V, ProgramError> {
600        let length = pod_get_packed_len::<V>();
601        let buffer = self.alloc::<V>(length, overwrite)?;
602        let extension_ref = pod_from_bytes_mut::<V>(buffer)?;
603        *extension_ref = V::default();
604        Ok(extension_ref)
605    }
606
607    /// Reallocate and overwite the TLV entry for the given variable-length
608    /// extension.
609    ///
610    /// Returns an error if the extension is not present, or if there is not
611    /// enough space in the buffer.
612    fn realloc_variable_len_extension<V: Extension + VariableLenPack>(
613        &mut self,
614        new_extension: &V,
615    ) -> Result<(), ProgramError> {
616        let data = self.realloc::<V>(new_extension.get_packed_len()?)?;
617        new_extension.pack_into_slice(data)
618    }
619
620    /// Reallocate the TLV entry for the given extension to the given number of
621    /// bytes.
622    ///
623    /// If the new length is smaller, it will compact the rest of the buffer and
624    /// zero out the difference at the end. If it's larger, it will move the
625    /// rest of the buffer data and zero out the new data.
626    ///
627    /// Returns an error if the extension is not present, or if this is not
628    /// enough space in the buffer.
629    fn realloc<V: Extension + VariableLenPack>(
630        &mut self,
631        length: usize,
632    ) -> Result<&mut [u8], ProgramError> {
633        let tlv_data = self.get_tlv_data_mut();
634        let TlvIndices {
635            type_start: _,
636            length_start,
637            value_start,
638        } = get_extension_indices::<V>(tlv_data, false)?;
639        let tlv_len = get_tlv_data_info(tlv_data).map(|x| x.used_len)?;
640        let data_len = tlv_data.len();
641
642        let length_ref = pod_from_bytes_mut::<Length>(&mut tlv_data[length_start..value_start])?;
643        let old_length = usize::from(*length_ref);
644
645        // Length check to avoid a panic later in `copy_within`
646        if old_length < length {
647            let new_tlv_len = tlv_len.saturating_add(length.saturating_sub(old_length));
648            if new_tlv_len > data_len {
649                return Err(ProgramError::InvalidAccountData);
650            }
651        }
652
653        // write new length after the check, to avoid getting into a bad situation
654        // if trying to recover from an error
655        *length_ref = Length::try_from(length)?;
656
657        let old_value_end = value_start.saturating_add(old_length);
658        let new_value_end = value_start.saturating_add(length);
659        tlv_data.copy_within(old_value_end..tlv_len, new_value_end);
660        match old_length.cmp(&length) {
661            Ordering::Greater => {
662                // realloc to smaller, zero out the end
663                let new_tlv_len = tlv_len.saturating_sub(old_length.saturating_sub(length));
664                tlv_data[new_tlv_len..tlv_len].fill(0);
665            }
666            Ordering::Less => {
667                // realloc to bigger, zero out the new bytes
668                tlv_data[old_value_end..new_value_end].fill(0);
669            }
670            Ordering::Equal => {} // nothing needed!
671        }
672
673        Ok(&mut tlv_data[value_start..new_value_end])
674    }
675
676    /// Allocate the given number of bytes for the given variable-length
677    /// extension and write its contents into the TLV buffer.
678    ///
679    /// This can only be used for variable-sized types, such as `String` or
680    /// `Vec`. `Pod` types must use `init_extension`
681    fn init_variable_len_extension<V: Extension + VariableLenPack>(
682        &mut self,
683        extension: &V,
684        overwrite: bool,
685    ) -> Result<(), ProgramError> {
686        let data = self.alloc::<V>(extension.get_packed_len()?, overwrite)?;
687        extension.pack_into_slice(data)
688    }
689
690    /// Allocate some space for the extension in the TLV data
691    fn alloc<V: Extension>(
692        &mut self,
693        length: usize,
694        overwrite: bool,
695    ) -> Result<&mut [u8], ProgramError> {
696        if V::TYPE.get_account_type() != S::ACCOUNT_TYPE {
697            return Err(ProgramError::InvalidAccountData);
698        }
699        let tlv_data = self.get_tlv_data_mut();
700        let TlvIndices {
701            type_start,
702            length_start,
703            value_start,
704        } = get_extension_indices::<V>(tlv_data, true)?;
705
706        if tlv_data[type_start..].len() < add_type_and_length_to_len(length) {
707            return Err(ProgramError::InvalidAccountData);
708        }
709        let extension_type = ExtensionType::try_from(&tlv_data[type_start..length_start])?;
710
711        if extension_type == ExtensionType::Uninitialized || overwrite {
712            // write extension type
713            let extension_type_array: [u8; 2] = V::TYPE.into();
714            let extension_type_ref = &mut tlv_data[type_start..length_start];
715            extension_type_ref.copy_from_slice(&extension_type_array);
716            // write length
717            let length_ref =
718                pod_from_bytes_mut::<Length>(&mut tlv_data[length_start..value_start])?;
719
720            // check that the length is the same if we're doing an alloc
721            // with overwrite, otherwise a realloc should be done
722            if overwrite && extension_type == V::TYPE && usize::from(*length_ref) != length {
723                return Err(TokenError::InvalidLengthForAlloc.into());
724            }
725
726            *length_ref = Length::try_from(length)?;
727
728            let value_end = value_start.saturating_add(length);
729            Ok(&mut tlv_data[value_start..value_end])
730        } else {
731            // extension is already initialized, but no overwrite permission
732            Err(TokenError::ExtensionAlreadyInitialized.into())
733        }
734    }
735
736    /// If `extension_type` is an Account-associated ExtensionType that requires
737    /// initialization on InitializeAccount, this method packs the default
738    /// relevant Extension of an ExtensionType into an open slot if not
739    /// already found in the data buffer, otherwise overwrites the
740    /// existing extension with the default state. For all other ExtensionTypes,
741    /// this is a no-op.
742    fn init_account_extension_from_type(
743        &mut self,
744        extension_type: ExtensionType,
745    ) -> Result<(), ProgramError> {
746        if extension_type.get_account_type() != AccountType::Account {
747            return Ok(());
748        }
749        match extension_type {
750            ExtensionType::TransferFeeAmount => {
751                self.init_extension::<TransferFeeAmount>(true).map(|_| ())
752            }
753            ExtensionType::ImmutableOwner => {
754                self.init_extension::<ImmutableOwner>(true).map(|_| ())
755            }
756            ExtensionType::NonTransferableAccount => self
757                .init_extension::<NonTransferableAccount>(true)
758                .map(|_| ()),
759            ExtensionType::TransferHookAccount => {
760                self.init_extension::<TransferHookAccount>(true).map(|_| ())
761            }
762            // ConfidentialTransfers are currently opt-in only, so this is a no-op for extra safety
763            // on InitializeAccount
764            ExtensionType::ConfidentialTransferAccount => Ok(()),
765            #[cfg(test)]
766            ExtensionType::AccountPaddingTest => {
767                self.init_extension::<AccountPaddingTest>(true).map(|_| ())
768            }
769            _ => unreachable!(),
770        }
771    }
772
773    /// Write the account type into the buffer, done during the base
774    /// state initialization
775    /// Noops if there is no room for an extension in the account, needed for
776    /// pure base mints / accounts.
777    fn init_account_type(&mut self) -> Result<(), ProgramError> {
778        let first_extension_type = self.get_first_extension_type()?;
779        let account_type = self.get_account_type_mut();
780        if !account_type.is_empty() {
781            if let Some(extension_type) = first_extension_type {
782                let account_type = extension_type.get_account_type();
783                if account_type != S::ACCOUNT_TYPE {
784                    return Err(TokenError::ExtensionBaseMismatch.into());
785                }
786            }
787            account_type[0] = S::ACCOUNT_TYPE.into();
788        }
789        Ok(())
790    }
791
792    /// Check that the account type on the account (if initialized) matches the
793    /// account type for any extensions initialized on the TLV data
794    fn check_account_type_matches_extension_type(&self) -> Result<(), ProgramError> {
795        if let Some(extension_type) = self.get_first_extension_type()? {
796            let account_type = extension_type.get_account_type();
797            if account_type != S::ACCOUNT_TYPE {
798                return Err(TokenError::ExtensionBaseMismatch.into());
799            }
800        }
801        Ok(())
802    }
803}
804
805/// Encapsulates mutable base state data (mint or account) with possible
806/// extensions
807#[derive(Debug, PartialEq)]
808pub struct StateWithExtensionsMut<'data, S: BaseState> {
809    /// Unpacked base data
810    pub base: S,
811    /// Raw base data
812    base_data: &'data mut [u8],
813    /// Writable account type
814    account_type: &'data mut [u8],
815    /// Slice of data containing all TLV data, deserialized on demand
816    tlv_data: &'data mut [u8],
817}
818impl<'data, S: BaseState + Pack> StateWithExtensionsMut<'data, S> {
819    /// Unpack base state, leaving the extension data as a mutable slice
820    ///
821    /// Fails if the base state is not initialized.
822    pub fn unpack(input: &'data mut [u8]) -> Result<Self, ProgramError> {
823        check_min_len_and_not_multisig(input, S::SIZE_OF)?;
824        let (base_data, rest) = input.split_at_mut(S::SIZE_OF);
825        let base = S::unpack(base_data)?;
826        let (account_type, tlv_data) = unpack_type_and_tlv_data_mut::<S>(rest)?;
827        Ok(Self {
828            base,
829            base_data,
830            account_type,
831            tlv_data,
832        })
833    }
834
835    /// Unpack an uninitialized base state, leaving the extension data as a
836    /// mutable slice
837    ///
838    /// Fails if the base state has already been initialized.
839    pub fn unpack_uninitialized(input: &'data mut [u8]) -> Result<Self, ProgramError> {
840        check_min_len_and_not_multisig(input, S::SIZE_OF)?;
841        let (base_data, rest) = input.split_at_mut(S::SIZE_OF);
842        let base = S::unpack_unchecked(base_data)?;
843        if base.is_initialized() {
844            return Err(TokenError::AlreadyInUse.into());
845        }
846        let (account_type, tlv_data) = unpack_uninitialized_type_and_tlv_data_mut::<S>(rest)?;
847        let state = Self {
848            base,
849            base_data,
850            account_type,
851            tlv_data,
852        };
853        state.check_account_type_matches_extension_type()?;
854        Ok(state)
855    }
856
857    /// Packs base state data into the base data portion
858    pub fn pack_base(&mut self) {
859        S::pack_into_slice(&self.base, self.base_data);
860    }
861}
862impl<'a, S: BaseState> BaseStateWithExtensions<S> for StateWithExtensionsMut<'a, S> {
863    fn get_tlv_data(&self) -> &[u8] {
864        self.tlv_data
865    }
866}
867impl<'a, S: BaseState> BaseStateWithExtensionsMut<S> for StateWithExtensionsMut<'a, S> {
868    fn get_tlv_data_mut(&mut self) -> &mut [u8] {
869        self.tlv_data
870    }
871    fn get_account_type_mut(&mut self) -> &mut [u8] {
872        self.account_type
873    }
874}
875
876/// Encapsulates mutable base state data (mint or account) with possible
877/// extensions, where the base state is Pod for zero-copy serde.
878#[derive(Debug, PartialEq)]
879pub struct PodStateWithExtensionsMut<'data, S: BaseState> {
880    /// Unpacked base data
881    pub base: &'data mut S,
882    /// Writable account type
883    account_type: &'data mut [u8],
884    /// Slice of data containing all TLV data, deserialized on demand
885    tlv_data: &'data mut [u8],
886}
887impl<'data, S: BaseState + Pod> PodStateWithExtensionsMut<'data, S> {
888    /// Unpack base state, leaving the extension data as a mutable slice
889    ///
890    /// Fails if the base state is not initialized.
891    pub fn unpack(input: &'data mut [u8]) -> Result<Self, ProgramError> {
892        check_min_len_and_not_multisig(input, S::SIZE_OF)?;
893        let (base_data, rest) = input.split_at_mut(S::SIZE_OF);
894        let base = pod_from_bytes_mut::<S>(base_data)?;
895        if !base.is_initialized() {
896            Err(ProgramError::UninitializedAccount)
897        } else {
898            let (account_type, tlv_data) = unpack_type_and_tlv_data_mut::<S>(rest)?;
899            Ok(Self {
900                base,
901                account_type,
902                tlv_data,
903            })
904        }
905    }
906
907    /// Unpack an uninitialized base state, leaving the extension data as a
908    /// mutable slice
909    ///
910    /// Fails if the base state has already been initialized.
911    pub fn unpack_uninitialized(input: &'data mut [u8]) -> Result<Self, ProgramError> {
912        check_min_len_and_not_multisig(input, S::SIZE_OF)?;
913        let (base_data, rest) = input.split_at_mut(S::SIZE_OF);
914        let base = pod_from_bytes_mut::<S>(base_data)?;
915        if base.is_initialized() {
916            return Err(TokenError::AlreadyInUse.into());
917        }
918        let (account_type, tlv_data) = unpack_uninitialized_type_and_tlv_data_mut::<S>(rest)?;
919        let state = Self {
920            base,
921            account_type,
922            tlv_data,
923        };
924        state.check_account_type_matches_extension_type()?;
925        Ok(state)
926    }
927}
928
929impl<'a, S: BaseState> BaseStateWithExtensions<S> for PodStateWithExtensionsMut<'a, S> {
930    fn get_tlv_data(&self) -> &[u8] {
931        self.tlv_data
932    }
933}
934impl<'a, S: BaseState> BaseStateWithExtensionsMut<S> for PodStateWithExtensionsMut<'a, S> {
935    fn get_tlv_data_mut(&mut self) -> &mut [u8] {
936        self.tlv_data
937    }
938    fn get_account_type_mut(&mut self) -> &mut [u8] {
939        self.account_type
940    }
941}
942
943fn unpack_tlv_data<S: BaseState>(rest: &[u8]) -> Result<&[u8], ProgramError> {
944    if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::<S>(rest)? {
945        // type_and_tlv_indices() checks that returned indexes are within range
946        let account_type = AccountType::try_from(rest[account_type_index])
947            .map_err(|_| ProgramError::InvalidAccountData)?;
948        check_account_type::<S>(account_type)?;
949        Ok(&rest[tlv_start_index..])
950    } else {
951        Ok(&[])
952    }
953}
954
955fn unpack_type_and_tlv_data_with_check_mut<
956    S: BaseState,
957    F: Fn(AccountType) -> Result<(), ProgramError>,
958>(
959    rest: &mut [u8],
960    check_fn: F,
961) -> Result<(&mut [u8], &mut [u8]), ProgramError> {
962    if let Some((account_type_index, tlv_start_index)) = type_and_tlv_indices::<S>(rest)? {
963        // type_and_tlv_indices() checks that returned indexes are within range
964        let account_type = AccountType::try_from(rest[account_type_index])
965            .map_err(|_| ProgramError::InvalidAccountData)?;
966        check_fn(account_type)?;
967        let (account_type, tlv_data) = rest.split_at_mut(tlv_start_index);
968        Ok((
969            &mut account_type[account_type_index..tlv_start_index],
970            tlv_data,
971        ))
972    } else {
973        Ok((&mut [], &mut []))
974    }
975}
976
977fn unpack_type_and_tlv_data_mut<S: BaseState>(
978    rest: &mut [u8],
979) -> Result<(&mut [u8], &mut [u8]), ProgramError> {
980    unpack_type_and_tlv_data_with_check_mut::<S, _>(rest, check_account_type::<S>)
981}
982
983fn unpack_uninitialized_type_and_tlv_data_mut<S: BaseState>(
984    rest: &mut [u8],
985) -> Result<(&mut [u8], &mut [u8]), ProgramError> {
986    unpack_type_and_tlv_data_with_check_mut::<S, _>(rest, |account_type| {
987        if account_type != AccountType::Uninitialized {
988            Err(ProgramError::InvalidAccountData)
989        } else {
990            Ok(())
991        }
992    })
993}
994
995/// If AccountType is uninitialized, set it to the BaseState's ACCOUNT_TYPE;
996/// if AccountType is already set, check is set correctly for BaseState
997/// This method assumes that the `base_data` has already been packed with data
998/// of the desired type.
999pub fn set_account_type<S: BaseState>(input: &mut [u8]) -> Result<(), ProgramError> {
1000    check_min_len_and_not_multisig(input, S::SIZE_OF)?;
1001    let (base_data, rest) = input.split_at_mut(S::SIZE_OF);
1002    if S::ACCOUNT_TYPE == AccountType::Account && !is_initialized_account(base_data)? {
1003        return Err(ProgramError::InvalidAccountData);
1004    }
1005    if let Some((account_type_index, _tlv_start_index)) = type_and_tlv_indices::<S>(rest)? {
1006        let mut account_type = AccountType::try_from(rest[account_type_index])
1007            .map_err(|_| ProgramError::InvalidAccountData)?;
1008        if account_type == AccountType::Uninitialized {
1009            rest[account_type_index] = S::ACCOUNT_TYPE.into();
1010            account_type = S::ACCOUNT_TYPE;
1011        }
1012        check_account_type::<S>(account_type)?;
1013        Ok(())
1014    } else {
1015        Err(ProgramError::InvalidAccountData)
1016    }
1017}
1018
1019/// Different kinds of accounts. Note that `Mint`, `Account`, and `Multisig`
1020/// types are determined exclusively by the size of the account, and are not
1021/// included in the account data. `AccountType` is only included if extensions
1022/// have been initialized.
1023#[repr(u8)]
1024#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)]
1025pub enum AccountType {
1026    /// Marker for 0 data
1027    Uninitialized,
1028    /// Mint account with additional extensions
1029    Mint,
1030    /// Token holding account with additional extensions
1031    Account,
1032}
1033impl Default for AccountType {
1034    fn default() -> Self {
1035        Self::Uninitialized
1036    }
1037}
1038
1039/// Extensions that can be applied to mints or accounts.  Mint extensions must
1040/// only be applied to mint accounts, and account extensions must only be
1041/// applied to token holding accounts.
1042#[repr(u16)]
1043#[cfg_attr(feature = "serde-traits", derive(Serialize, Deserialize))]
1044#[cfg_attr(feature = "serde-traits", serde(rename_all = "camelCase"))]
1045#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)]
1046pub enum ExtensionType {
1047    /// Used as padding if the account size would otherwise be 355, same as a
1048    /// multisig
1049    Uninitialized,
1050    /// Includes transfer fee rate info and accompanying authorities to withdraw
1051    /// and set the fee
1052    TransferFeeConfig,
1053    /// Includes withheld transfer fees
1054    TransferFeeAmount,
1055    /// Includes an optional mint close authority
1056    MintCloseAuthority,
1057    /// Auditor configuration for confidential transfers
1058    ConfidentialTransferMint,
1059    /// State for confidential transfers
1060    ConfidentialTransferAccount,
1061    /// Specifies the default Account::state for new Accounts
1062    DefaultAccountState,
1063    /// Indicates that the Account owner authority cannot be changed
1064    ImmutableOwner,
1065    /// Require inbound transfers to have memo
1066    MemoTransfer,
1067    /// Indicates that the tokens from this mint can't be transferred
1068    NonTransferable,
1069    /// Tokens accrue interest over time,
1070    InterestBearingConfig,
1071    /// Locks privileged token operations from happening via CPI
1072    CpiGuard,
1073    /// Includes an optional permanent delegate
1074    PermanentDelegate,
1075    /// Indicates that the tokens in this account belong to a non-transferable
1076    /// mint
1077    NonTransferableAccount,
1078    /// Mint requires a CPI to a program implementing the "transfer hook"
1079    /// interface
1080    TransferHook,
1081    /// Indicates that the tokens in this account belong to a mint with a
1082    /// transfer hook
1083    TransferHookAccount,
1084    /// Includes encrypted withheld fees and the encryption public that they are
1085    /// encrypted under
1086    ConfidentialTransferFeeConfig,
1087    /// Includes confidential withheld transfer fees
1088    ConfidentialTransferFeeAmount,
1089    /// Mint contains a pointer to another account (or the same account) that
1090    /// holds metadata
1091    MetadataPointer,
1092    /// Mint contains token-metadata
1093    TokenMetadata,
1094    /// Mint contains a pointer to another account (or the same account) that
1095    /// holds group configurations
1096    GroupPointer,
1097    /// Mint contains token group configurations
1098    TokenGroup,
1099    /// Mint contains a pointer to another account (or the same account) that
1100    /// holds group member configurations
1101    GroupMemberPointer,
1102    /// Mint contains token group member configurations
1103    TokenGroupMember,
1104    /// Test variable-length mint extension
1105    #[cfg(test)]
1106    VariableLenMintTest = u16::MAX - 2,
1107    /// Padding extension used to make an account exactly Multisig::LEN, used
1108    /// for testing
1109    #[cfg(test)]
1110    AccountPaddingTest,
1111    /// Padding extension used to make a mint exactly Multisig::LEN, used for
1112    /// testing
1113    #[cfg(test)]
1114    MintPaddingTest,
1115}
1116impl TryFrom<&[u8]> for ExtensionType {
1117    type Error = ProgramError;
1118    fn try_from(a: &[u8]) -> Result<Self, Self::Error> {
1119        Self::try_from(u16::from_le_bytes(
1120            a.try_into().map_err(|_| ProgramError::InvalidAccountData)?,
1121        ))
1122        .map_err(|_| ProgramError::InvalidAccountData)
1123    }
1124}
1125impl From<ExtensionType> for [u8; 2] {
1126    fn from(a: ExtensionType) -> Self {
1127        u16::from(a).to_le_bytes()
1128    }
1129}
1130impl ExtensionType {
1131    /// Returns true if the given extension type is sized
1132    ///
1133    /// Most extension types should be sized, so any variable-length extension
1134    /// types should be added here by hand
1135    const fn sized(&self) -> bool {
1136        match self {
1137            ExtensionType::TokenMetadata => false,
1138            #[cfg(test)]
1139            ExtensionType::VariableLenMintTest => false,
1140            _ => true,
1141        }
1142    }
1143
1144    /// Get the data length of the type associated with the enum
1145    ///
1146    /// Fails if the extension type has a variable length
1147    fn try_get_type_len(&self) -> Result<usize, ProgramError> {
1148        if !self.sized() {
1149            return Err(ProgramError::InvalidArgument);
1150        }
1151        Ok(match self {
1152            ExtensionType::Uninitialized => 0,
1153            ExtensionType::TransferFeeConfig => pod_get_packed_len::<TransferFeeConfig>(),
1154            ExtensionType::TransferFeeAmount => pod_get_packed_len::<TransferFeeAmount>(),
1155            ExtensionType::MintCloseAuthority => pod_get_packed_len::<MintCloseAuthority>(),
1156            ExtensionType::ImmutableOwner => pod_get_packed_len::<ImmutableOwner>(),
1157            ExtensionType::ConfidentialTransferMint => {
1158                pod_get_packed_len::<ConfidentialTransferMint>()
1159            }
1160            ExtensionType::ConfidentialTransferAccount => {
1161                pod_get_packed_len::<ConfidentialTransferAccount>()
1162            }
1163            ExtensionType::DefaultAccountState => pod_get_packed_len::<DefaultAccountState>(),
1164            ExtensionType::MemoTransfer => pod_get_packed_len::<MemoTransfer>(),
1165            ExtensionType::NonTransferable => pod_get_packed_len::<NonTransferable>(),
1166            ExtensionType::InterestBearingConfig => pod_get_packed_len::<InterestBearingConfig>(),
1167            ExtensionType::CpiGuard => pod_get_packed_len::<CpiGuard>(),
1168            ExtensionType::PermanentDelegate => pod_get_packed_len::<PermanentDelegate>(),
1169            ExtensionType::NonTransferableAccount => pod_get_packed_len::<NonTransferableAccount>(),
1170            ExtensionType::TransferHook => pod_get_packed_len::<TransferHook>(),
1171            ExtensionType::TransferHookAccount => pod_get_packed_len::<TransferHookAccount>(),
1172            ExtensionType::ConfidentialTransferFeeConfig => {
1173                pod_get_packed_len::<ConfidentialTransferFeeConfig>()
1174            }
1175            ExtensionType::ConfidentialTransferFeeAmount => {
1176                pod_get_packed_len::<ConfidentialTransferFeeAmount>()
1177            }
1178            ExtensionType::MetadataPointer => pod_get_packed_len::<MetadataPointer>(),
1179            ExtensionType::TokenMetadata => unreachable!(),
1180            ExtensionType::GroupPointer => pod_get_packed_len::<GroupPointer>(),
1181            ExtensionType::TokenGroup => pod_get_packed_len::<TokenGroup>(),
1182            ExtensionType::GroupMemberPointer => pod_get_packed_len::<GroupMemberPointer>(),
1183            ExtensionType::TokenGroupMember => pod_get_packed_len::<TokenGroupMember>(),
1184            #[cfg(test)]
1185            ExtensionType::AccountPaddingTest => pod_get_packed_len::<AccountPaddingTest>(),
1186            #[cfg(test)]
1187            ExtensionType::MintPaddingTest => pod_get_packed_len::<MintPaddingTest>(),
1188            #[cfg(test)]
1189            ExtensionType::VariableLenMintTest => unreachable!(),
1190        })
1191    }
1192
1193    /// Get the TLV length for an ExtensionType
1194    ///
1195    /// Fails if the extension type has a variable length
1196    fn try_get_tlv_len(&self) -> Result<usize, ProgramError> {
1197        Ok(add_type_and_length_to_len(self.try_get_type_len()?))
1198    }
1199
1200    /// Get the TLV length for a set of ExtensionTypes
1201    ///
1202    /// Fails if any of the extension types has a variable length
1203    fn try_get_total_tlv_len(extension_types: &[Self]) -> Result<usize, ProgramError> {
1204        // dedupe extensions
1205        let mut extensions = vec![];
1206        for extension_type in extension_types {
1207            if !extensions.contains(&extension_type) {
1208                extensions.push(extension_type);
1209            }
1210        }
1211        extensions.iter().map(|e| e.try_get_tlv_len()).sum()
1212    }
1213
1214    /// Get the required account data length for the given ExtensionTypes
1215    ///
1216    /// Fails if any of the extension types has a variable length
1217    pub fn try_calculate_account_len<S: BaseState>(
1218        extension_types: &[Self],
1219    ) -> Result<usize, ProgramError> {
1220        if extension_types.is_empty() {
1221            Ok(S::SIZE_OF)
1222        } else {
1223            let extension_size = Self::try_get_total_tlv_len(extension_types)?;
1224            let total_len = extension_size.saturating_add(BASE_ACCOUNT_AND_TYPE_LENGTH);
1225            Ok(adjust_len_for_multisig(total_len))
1226        }
1227    }
1228
1229    /// Get the associated account type
1230    pub fn get_account_type(&self) -> AccountType {
1231        match self {
1232            ExtensionType::Uninitialized => AccountType::Uninitialized,
1233            ExtensionType::TransferFeeConfig
1234            | ExtensionType::MintCloseAuthority
1235            | ExtensionType::ConfidentialTransferMint
1236            | ExtensionType::DefaultAccountState
1237            | ExtensionType::NonTransferable
1238            | ExtensionType::InterestBearingConfig
1239            | ExtensionType::PermanentDelegate
1240            | ExtensionType::TransferHook
1241            | ExtensionType::ConfidentialTransferFeeConfig
1242            | ExtensionType::MetadataPointer
1243            | ExtensionType::TokenMetadata
1244            | ExtensionType::GroupPointer
1245            | ExtensionType::TokenGroup
1246            | ExtensionType::GroupMemberPointer
1247            | ExtensionType::TokenGroupMember => AccountType::Mint,
1248            ExtensionType::ImmutableOwner
1249            | ExtensionType::TransferFeeAmount
1250            | ExtensionType::ConfidentialTransferAccount
1251            | ExtensionType::MemoTransfer
1252            | ExtensionType::NonTransferableAccount
1253            | ExtensionType::TransferHookAccount
1254            | ExtensionType::CpiGuard
1255            | ExtensionType::ConfidentialTransferFeeAmount => AccountType::Account,
1256            #[cfg(test)]
1257            ExtensionType::VariableLenMintTest => AccountType::Mint,
1258            #[cfg(test)]
1259            ExtensionType::AccountPaddingTest => AccountType::Account,
1260            #[cfg(test)]
1261            ExtensionType::MintPaddingTest => AccountType::Mint,
1262        }
1263    }
1264
1265    /// Based on a set of AccountType::Mint ExtensionTypes, get the list of
1266    /// AccountType::Account ExtensionTypes required on InitializeAccount
1267    pub fn get_required_init_account_extensions(mint_extension_types: &[Self]) -> Vec<Self> {
1268        let mut account_extension_types = vec![];
1269        for extension_type in mint_extension_types {
1270            match extension_type {
1271                ExtensionType::TransferFeeConfig => {
1272                    account_extension_types.push(ExtensionType::TransferFeeAmount);
1273                }
1274                ExtensionType::NonTransferable => {
1275                    account_extension_types.push(ExtensionType::NonTransferableAccount);
1276                    account_extension_types.push(ExtensionType::ImmutableOwner);
1277                }
1278                ExtensionType::TransferHook => {
1279                    account_extension_types.push(ExtensionType::TransferHookAccount);
1280                }
1281                #[cfg(test)]
1282                ExtensionType::MintPaddingTest => {
1283                    account_extension_types.push(ExtensionType::AccountPaddingTest);
1284                }
1285                _ => {}
1286            }
1287        }
1288        account_extension_types
1289    }
1290
1291    /// Check for invalid combination of mint extensions
1292    pub fn check_for_invalid_mint_extension_combinations(
1293        mint_extension_types: &[Self],
1294    ) -> Result<(), TokenError> {
1295        let mut transfer_fee_config = false;
1296        let mut confidential_transfer_mint = false;
1297        let mut confidential_transfer_fee_config = false;
1298
1299        for extension_type in mint_extension_types {
1300            match extension_type {
1301                ExtensionType::TransferFeeConfig => transfer_fee_config = true,
1302                ExtensionType::ConfidentialTransferMint => confidential_transfer_mint = true,
1303                ExtensionType::ConfidentialTransferFeeConfig => {
1304                    confidential_transfer_fee_config = true
1305                }
1306                _ => (),
1307            }
1308        }
1309
1310        if confidential_transfer_fee_config && !(transfer_fee_config && confidential_transfer_mint)
1311        {
1312            return Err(TokenError::InvalidExtensionCombination);
1313        }
1314
1315        if transfer_fee_config && confidential_transfer_mint && !confidential_transfer_fee_config {
1316            return Err(TokenError::InvalidExtensionCombination);
1317        }
1318
1319        Ok(())
1320    }
1321}
1322
1323/// Trait for base states, specifying the associated enum
1324pub trait BaseState: PackedSizeOf + IsInitialized {
1325    /// Associated extension type enum, checked at the start of TLV entries
1326    const ACCOUNT_TYPE: AccountType;
1327}
1328impl BaseState for Account {
1329    const ACCOUNT_TYPE: AccountType = AccountType::Account;
1330}
1331impl BaseState for Mint {
1332    const ACCOUNT_TYPE: AccountType = AccountType::Mint;
1333}
1334impl BaseState for PodAccount {
1335    const ACCOUNT_TYPE: AccountType = AccountType::Account;
1336}
1337impl BaseState for PodMint {
1338    const ACCOUNT_TYPE: AccountType = AccountType::Mint;
1339}
1340
1341/// Trait to be implemented by all extension states, specifying which extension
1342/// and account type they are associated with
1343pub trait Extension {
1344    /// Associated extension type enum, checked at the start of TLV entries
1345    const TYPE: ExtensionType;
1346}
1347
1348/// Padding a mint account to be exactly Multisig::LEN.
1349/// We need to pad 185 bytes, since Multisig::LEN = 355, Account::LEN = 165,
1350/// size_of AccountType = 1, size_of ExtensionType = 2, size_of Length = 2.
1351/// 355 - 165 - 1 - 2 - 2 = 185
1352#[cfg(test)]
1353#[repr(C)]
1354#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
1355pub struct MintPaddingTest {
1356    /// Largest value under 185 that implements Pod
1357    pub padding1: [u8; 128],
1358    /// Largest value under 57 that implements Pod
1359    pub padding2: [u8; 48],
1360    /// Exact value needed to finish the padding
1361    pub padding3: [u8; 9],
1362}
1363#[cfg(test)]
1364impl Extension for MintPaddingTest {
1365    const TYPE: ExtensionType = ExtensionType::MintPaddingTest;
1366}
1367#[cfg(test)]
1368impl Default for MintPaddingTest {
1369    fn default() -> Self {
1370        Self {
1371            padding1: [1; 128],
1372            padding2: [2; 48],
1373            padding3: [3; 9],
1374        }
1375    }
1376}
1377/// Account version of the MintPadding
1378#[cfg(test)]
1379#[repr(C)]
1380#[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
1381pub struct AccountPaddingTest(MintPaddingTest);
1382#[cfg(test)]
1383impl Extension for AccountPaddingTest {
1384    const TYPE: ExtensionType = ExtensionType::AccountPaddingTest;
1385}
1386
1387/// Packs a fixed-length extension into a TLV space
1388///
1389/// This function reallocates the account as needed to accommodate for the
1390/// change in space.
1391///
1392/// If the extension already exists, it will overwrite the existing extension
1393/// if `overwrite` is `true`, otherwise it will return an error.
1394///
1395/// If the extension does not exist, it will reallocate the account and write
1396/// the extension into the TLV buffer.
1397///
1398/// NOTE: Since this function deals with fixed-size extensions, it does not
1399/// handle _decreasing_ the size of an account's data buffer, like the function
1400/// `alloc_and_serialize_variable_len_extension` does.
1401pub(crate) fn alloc_and_serialize<S: BaseState + Pod, V: Default + Extension + Pod>(
1402    account_info: &AccountInfo,
1403    new_extension: &V,
1404    overwrite: bool,
1405) -> Result<(), ProgramError> {
1406    let previous_account_len = account_info.try_data_len()?;
1407    let new_account_len = {
1408        let data = account_info.try_borrow_data()?;
1409        let state = PodStateWithExtensions::<S>::unpack(&data)?;
1410        state.try_get_new_account_len::<V>()?
1411    };
1412
1413    // Realloc the account first, if needed
1414    if new_account_len > previous_account_len {
1415        account_info.realloc(new_account_len, false)?;
1416    }
1417    let mut buffer = account_info.try_borrow_mut_data()?;
1418    if previous_account_len <= BASE_ACCOUNT_LENGTH {
1419        set_account_type::<S>(*buffer)?;
1420    }
1421    let mut state = PodStateWithExtensionsMut::<S>::unpack(&mut buffer)?;
1422
1423    // Write the extension
1424    let extension = state.init_extension::<V>(overwrite)?;
1425    *extension = *new_extension;
1426
1427    Ok(())
1428}
1429
1430/// Packs a variable-length extension into a TLV space
1431///
1432/// This function reallocates the account as needed to accommodate for the
1433/// change in space, then reallocates in the TLV buffer, and finally writes the
1434/// bytes.
1435///
1436/// NOTE: Unlike the `reallocate` instruction, this function will reduce the
1437/// size of an account if it has too many bytes allocated for the given value.
1438pub(crate) fn alloc_and_serialize_variable_len_extension<
1439    S: BaseState + Pod,
1440    V: Extension + VariableLenPack,
1441>(
1442    account_info: &AccountInfo,
1443    new_extension: &V,
1444    overwrite: bool,
1445) -> Result<(), ProgramError> {
1446    let previous_account_len = account_info.try_data_len()?;
1447    let (new_account_len, extension_already_exists) = {
1448        let data = account_info.try_borrow_data()?;
1449        let state = PodStateWithExtensions::<S>::unpack(&data)?;
1450        let new_account_len =
1451            state.try_get_new_account_len_for_variable_len_extension(new_extension)?;
1452        let extension_already_exists = state.get_extension_bytes::<V>().is_ok();
1453        (new_account_len, extension_already_exists)
1454    };
1455
1456    if extension_already_exists && !overwrite {
1457        return Err(TokenError::ExtensionAlreadyInitialized.into());
1458    }
1459
1460    if previous_account_len < new_account_len {
1461        // account size increased, so realloc the account, then the TLV entry, then
1462        // write data
1463        account_info.realloc(new_account_len, false)?;
1464        let mut buffer = account_info.try_borrow_mut_data()?;
1465        if extension_already_exists {
1466            let mut state = PodStateWithExtensionsMut::<S>::unpack(&mut buffer)?;
1467            state.realloc_variable_len_extension(new_extension)?;
1468        } else {
1469            if previous_account_len <= BASE_ACCOUNT_LENGTH {
1470                set_account_type::<S>(*buffer)?;
1471            }
1472            // now alloc in the TLV buffer and write the data
1473            let mut state = PodStateWithExtensionsMut::<S>::unpack(&mut buffer)?;
1474            state.init_variable_len_extension(new_extension, false)?;
1475        }
1476    } else {
1477        // do it backwards otherwise, write the state, realloc TLV, then the account
1478        let mut buffer = account_info.try_borrow_mut_data()?;
1479        let mut state = PodStateWithExtensionsMut::<S>::unpack(&mut buffer)?;
1480        if extension_already_exists {
1481            state.realloc_variable_len_extension(new_extension)?;
1482        } else {
1483            // this situation can happen if we have an overallocated buffer
1484            state.init_variable_len_extension(new_extension, false)?;
1485        }
1486
1487        let removed_bytes = previous_account_len
1488            .checked_sub(new_account_len)
1489            .ok_or(ProgramError::AccountDataTooSmall)?;
1490        if removed_bytes > 0 {
1491            // this is probably fine, but be safe and avoid invalidating references
1492            drop(buffer);
1493            account_info.realloc(new_account_len, false)?;
1494        }
1495    }
1496    Ok(())
1497}
1498
1499#[cfg(test)]
1500mod test {
1501    use {
1502        super::*,
1503        crate::{
1504            pod::test::{TEST_POD_ACCOUNT, TEST_POD_MINT},
1505            state::test::{TEST_ACCOUNT_SLICE, TEST_MINT_SLICE},
1506        },
1507        bytemuck::Pod,
1508        miraland_program::{
1509            account_info::{Account as GetAccount, IntoAccountInfo},
1510            clock::Epoch,
1511            entrypoint::MAX_PERMITTED_DATA_INCREASE,
1512            pubkey::Pubkey,
1513        },
1514        spl_pod::{
1515            bytemuck::pod_bytes_of, optional_keys::OptionalNonZeroPubkey, primitives::PodU64,
1516        },
1517        transfer_fee::test::test_transfer_fee_config,
1518    };
1519
1520    /// Test fixed-length struct
1521    #[repr(C)]
1522    #[derive(Clone, Copy, Debug, Default, PartialEq, Pod, Zeroable)]
1523    struct FixedLenMintTest {
1524        data: [u8; 8],
1525    }
1526    impl Extension for FixedLenMintTest {
1527        const TYPE: ExtensionType = ExtensionType::MintPaddingTest;
1528    }
1529
1530    /// Test variable-length struct
1531    #[derive(Clone, Debug, PartialEq)]
1532    struct VariableLenMintTest {
1533        data: Vec<u8>,
1534    }
1535    impl Extension for VariableLenMintTest {
1536        const TYPE: ExtensionType = ExtensionType::VariableLenMintTest;
1537    }
1538    impl VariableLenPack for VariableLenMintTest {
1539        fn pack_into_slice(&self, dst: &mut [u8]) -> Result<(), ProgramError> {
1540            let data_start = size_of::<u64>();
1541            let end = data_start + self.data.len();
1542            if dst.len() < end {
1543                Err(ProgramError::InvalidAccountData)
1544            } else {
1545                dst[..data_start].copy_from_slice(&self.data.len().to_le_bytes());
1546                dst[data_start..end].copy_from_slice(&self.data);
1547                Ok(())
1548            }
1549        }
1550        fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
1551            let data_start = size_of::<u64>();
1552            let length = u64::from_le_bytes(src[..data_start].try_into().unwrap()) as usize;
1553            if src[data_start..data_start + length].len() != length {
1554                return Err(ProgramError::InvalidAccountData);
1555            }
1556            let data = Vec::from(&src[data_start..data_start + length]);
1557            Ok(Self { data })
1558        }
1559        fn get_packed_len(&self) -> Result<usize, ProgramError> {
1560            Ok(size_of::<u64>().saturating_add(self.data.len()))
1561        }
1562    }
1563
1564    const MINT_WITH_EXTENSION: &[u8] = &[
1565        1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1566        1, 1, 1, 1, 1, 1, 42, 0, 0, 0, 0, 0, 0, 0, 7, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1567        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // base mint
1568        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1569        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1570        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // padding
1571        1, // account type
1572        3, 0, // extension type
1573        32, 0, // length
1574        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1575        1, 1, // data
1576    ];
1577
1578    #[test]
1579    fn unpack_opaque_buffer() {
1580        let state = PodStateWithExtensions::<PodMint>::unpack(MINT_WITH_EXTENSION).unwrap();
1581        assert_eq!(state.base, &TEST_POD_MINT);
1582        let extension = state.get_extension::<MintCloseAuthority>().unwrap();
1583        let close_authority =
1584            OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([1; 32]))).unwrap();
1585        assert_eq!(extension.close_authority, close_authority);
1586        assert_eq!(
1587            state.get_extension::<TransferFeeConfig>(),
1588            Err(ProgramError::InvalidAccountData)
1589        );
1590        assert_eq!(
1591            PodStateWithExtensions::<PodAccount>::unpack(MINT_WITH_EXTENSION),
1592            Err(ProgramError::UninitializedAccount)
1593        );
1594
1595        let state = PodStateWithExtensions::<PodMint>::unpack(TEST_MINT_SLICE).unwrap();
1596        assert_eq!(state.base, &TEST_POD_MINT);
1597
1598        let mut test_mint = TEST_MINT_SLICE.to_vec();
1599        let state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut test_mint).unwrap();
1600        assert_eq!(state.base, &TEST_POD_MINT);
1601    }
1602
1603    #[test]
1604    fn fail_unpack_opaque_buffer() {
1605        // input buffer too small
1606        let mut buffer = vec![0, 3];
1607        assert_eq!(
1608            PodStateWithExtensions::<PodMint>::unpack(&buffer),
1609            Err(ProgramError::InvalidAccountData)
1610        );
1611        assert_eq!(
1612            PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer),
1613            Err(ProgramError::InvalidAccountData)
1614        );
1615        assert_eq!(
1616            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer),
1617            Err(ProgramError::InvalidAccountData)
1618        );
1619
1620        // tweak the account type
1621        let mut buffer = MINT_WITH_EXTENSION.to_vec();
1622        buffer[BASE_ACCOUNT_LENGTH] = 3;
1623        assert_eq!(
1624            PodStateWithExtensions::<PodMint>::unpack(&buffer),
1625            Err(ProgramError::InvalidAccountData)
1626        );
1627
1628        // clear the mint initialized byte
1629        let mut buffer = MINT_WITH_EXTENSION.to_vec();
1630        buffer[45] = 0;
1631        assert_eq!(
1632            PodStateWithExtensions::<PodMint>::unpack(&buffer),
1633            Err(ProgramError::UninitializedAccount)
1634        );
1635
1636        // tweak the padding
1637        let mut buffer = MINT_WITH_EXTENSION.to_vec();
1638        buffer[PodMint::SIZE_OF] = 100;
1639        assert_eq!(
1640            PodStateWithExtensions::<PodMint>::unpack(&buffer),
1641            Err(ProgramError::InvalidAccountData)
1642        );
1643
1644        // tweak the extension type
1645        let mut buffer = MINT_WITH_EXTENSION.to_vec();
1646        buffer[BASE_ACCOUNT_LENGTH + 1] = 2;
1647        let state = PodStateWithExtensions::<PodMint>::unpack(&buffer).unwrap();
1648        assert_eq!(
1649            state.get_extension::<TransferFeeConfig>(),
1650            Err(ProgramError::Custom(
1651                TokenError::ExtensionTypeMismatch as u32
1652            ))
1653        );
1654
1655        // tweak the length, too big
1656        let mut buffer = MINT_WITH_EXTENSION.to_vec();
1657        buffer[BASE_ACCOUNT_LENGTH + 3] = 100;
1658        let state = PodStateWithExtensions::<PodMint>::unpack(&buffer).unwrap();
1659        assert_eq!(
1660            state.get_extension::<TransferFeeConfig>(),
1661            Err(ProgramError::InvalidAccountData)
1662        );
1663
1664        // tweak the length, too small
1665        let mut buffer = MINT_WITH_EXTENSION.to_vec();
1666        buffer[BASE_ACCOUNT_LENGTH + 3] = 10;
1667        let state = PodStateWithExtensions::<PodMint>::unpack(&buffer).unwrap();
1668        assert_eq!(
1669            state.get_extension::<TransferFeeConfig>(),
1670            Err(ProgramError::InvalidAccountData)
1671        );
1672
1673        // data buffer is too small
1674        let buffer = &MINT_WITH_EXTENSION[..MINT_WITH_EXTENSION.len() - 1];
1675        let state = PodStateWithExtensions::<PodMint>::unpack(buffer).unwrap();
1676        assert_eq!(
1677            state.get_extension::<MintCloseAuthority>(),
1678            Err(ProgramError::InvalidAccountData)
1679        );
1680    }
1681
1682    #[test]
1683    fn get_extension_types_with_opaque_buffer() {
1684        // incorrect due to the length
1685        assert_eq!(
1686            get_tlv_data_info(&[1, 0, 1, 1]).unwrap_err(),
1687            ProgramError::InvalidAccountData,
1688        );
1689        // incorrect due to the huge enum number
1690        assert_eq!(
1691            get_tlv_data_info(&[0, 1, 0, 0]).unwrap_err(),
1692            ProgramError::InvalidAccountData,
1693        );
1694        // correct due to the good enum number and zero length
1695        assert_eq!(
1696            get_tlv_data_info(&[1, 0, 0, 0]).unwrap(),
1697            TlvDataInfo {
1698                extension_types: vec![ExtensionType::try_from(1).unwrap()],
1699                used_len: add_type_and_length_to_len(0),
1700            }
1701        );
1702        // correct since it's just uninitialized data at the end
1703        assert_eq!(
1704            get_tlv_data_info(&[0, 0]).unwrap(),
1705            TlvDataInfo {
1706                extension_types: vec![],
1707                used_len: 0
1708            }
1709        );
1710    }
1711
1712    #[test]
1713    fn mint_with_extension_pack_unpack() {
1714        let mint_size = ExtensionType::try_calculate_account_len::<PodMint>(&[
1715            ExtensionType::MintCloseAuthority,
1716            ExtensionType::TransferFeeConfig,
1717        ])
1718        .unwrap();
1719        let mut buffer = vec![0; mint_size];
1720
1721        // fail unpack
1722        assert_eq!(
1723            PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer),
1724            Err(ProgramError::UninitializedAccount),
1725        );
1726
1727        let mut state =
1728            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
1729        // fail init account extension
1730        assert_eq!(
1731            state.init_extension::<TransferFeeAmount>(true),
1732            Err(ProgramError::InvalidAccountData),
1733        );
1734
1735        // success write extension
1736        let close_authority =
1737            OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([1; 32]))).unwrap();
1738        let extension = state.init_extension::<MintCloseAuthority>(true).unwrap();
1739        extension.close_authority = close_authority;
1740        assert_eq!(
1741            &state.get_extension_types().unwrap(),
1742            &[ExtensionType::MintCloseAuthority]
1743        );
1744
1745        // fail init extension when already initialized
1746        assert_eq!(
1747            state.init_extension::<MintCloseAuthority>(false),
1748            Err(ProgramError::Custom(
1749                TokenError::ExtensionAlreadyInitialized as u32
1750            ))
1751        );
1752
1753        // fail unpack as account, a mint extension was written
1754        assert_eq!(
1755            PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer),
1756            Err(ProgramError::Custom(
1757                TokenError::ExtensionBaseMismatch as u32
1758            ))
1759        );
1760
1761        // fail unpack again, still no base data
1762        assert_eq!(
1763            PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer.clone()),
1764            Err(ProgramError::UninitializedAccount),
1765        );
1766
1767        // write base mint
1768        let mut state =
1769            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
1770        *state.base = TEST_POD_MINT;
1771        state.init_account_type().unwrap();
1772
1773        // check raw buffer
1774        let mut expect = TEST_MINT_SLICE.to_vec();
1775        expect.extend_from_slice(&[0; BASE_ACCOUNT_LENGTH - PodMint::SIZE_OF]); // padding
1776        expect.push(AccountType::Mint.into());
1777        expect.extend_from_slice(&(ExtensionType::MintCloseAuthority as u16).to_le_bytes());
1778        expect
1779            .extend_from_slice(&(pod_get_packed_len::<MintCloseAuthority>() as u16).to_le_bytes());
1780        expect.extend_from_slice(&[1; 32]); // data
1781        expect.extend_from_slice(&[0; size_of::<ExtensionType>()]);
1782        expect.extend_from_slice(&[0; size_of::<Length>()]);
1783        expect.extend_from_slice(&[0; size_of::<TransferFeeConfig>()]);
1784        assert_eq!(expect, buffer);
1785
1786        // unpack uninitialized will now fail because the PodMint is now initialized
1787        assert_eq!(
1788            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer.clone()),
1789            Err(TokenError::AlreadyInUse.into()),
1790        );
1791
1792        // check unpacking
1793        let mut state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap();
1794
1795        // update base
1796        *state.base = TEST_POD_MINT;
1797        state.base.supply = (u64::from(state.base.supply) + 100).into();
1798
1799        // check unpacking
1800        let unpacked_extension = state.get_extension_mut::<MintCloseAuthority>().unwrap();
1801        assert_eq!(*unpacked_extension, MintCloseAuthority { close_authority });
1802
1803        // update extension
1804        let close_authority = OptionalNonZeroPubkey::try_from(None).unwrap();
1805        unpacked_extension.close_authority = close_authority;
1806
1807        // check updates are propagated
1808        let base = *state.base;
1809        let state = PodStateWithExtensions::<PodMint>::unpack(&buffer).unwrap();
1810        assert_eq!(state.base, &base);
1811        let unpacked_extension = state.get_extension::<MintCloseAuthority>().unwrap();
1812        assert_eq!(*unpacked_extension, MintCloseAuthority { close_authority });
1813
1814        // check raw buffer
1815        let mut expect = vec![];
1816        expect.extend_from_slice(bytemuck::bytes_of(&base));
1817        expect.extend_from_slice(&[0; BASE_ACCOUNT_LENGTH - PodMint::SIZE_OF]); // padding
1818        expect.push(AccountType::Mint.into());
1819        expect.extend_from_slice(&(ExtensionType::MintCloseAuthority as u16).to_le_bytes());
1820        expect
1821            .extend_from_slice(&(pod_get_packed_len::<MintCloseAuthority>() as u16).to_le_bytes());
1822        expect.extend_from_slice(&[0; 32]);
1823        expect.extend_from_slice(&[0; size_of::<ExtensionType>()]);
1824        expect.extend_from_slice(&[0; size_of::<Length>()]);
1825        expect.extend_from_slice(&[0; size_of::<TransferFeeConfig>()]);
1826        assert_eq!(expect, buffer);
1827
1828        // fail unpack as an account
1829        assert_eq!(
1830            PodStateWithExtensions::<PodAccount>::unpack(&buffer),
1831            Err(ProgramError::UninitializedAccount),
1832        );
1833
1834        let mut state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap();
1835        // init one more extension
1836        let mint_transfer_fee = test_transfer_fee_config();
1837        let new_extension = state.init_extension::<TransferFeeConfig>(true).unwrap();
1838        new_extension.transfer_fee_config_authority =
1839            mint_transfer_fee.transfer_fee_config_authority;
1840        new_extension.withdraw_withheld_authority = mint_transfer_fee.withdraw_withheld_authority;
1841        new_extension.withheld_amount = mint_transfer_fee.withheld_amount;
1842        new_extension.older_transfer_fee = mint_transfer_fee.older_transfer_fee;
1843        new_extension.newer_transfer_fee = mint_transfer_fee.newer_transfer_fee;
1844
1845        assert_eq!(
1846            &state.get_extension_types().unwrap(),
1847            &[
1848                ExtensionType::MintCloseAuthority,
1849                ExtensionType::TransferFeeConfig
1850            ]
1851        );
1852
1853        // check raw buffer
1854        let mut expect = vec![];
1855        expect.extend_from_slice(pod_bytes_of(&base));
1856        expect.extend_from_slice(&[0; BASE_ACCOUNT_LENGTH - PodMint::SIZE_OF]); // padding
1857        expect.push(AccountType::Mint.into());
1858        expect.extend_from_slice(&(ExtensionType::MintCloseAuthority as u16).to_le_bytes());
1859        expect
1860            .extend_from_slice(&(pod_get_packed_len::<MintCloseAuthority>() as u16).to_le_bytes());
1861        expect.extend_from_slice(&[0; 32]); // data
1862        expect.extend_from_slice(&(ExtensionType::TransferFeeConfig as u16).to_le_bytes());
1863        expect.extend_from_slice(&(pod_get_packed_len::<TransferFeeConfig>() as u16).to_le_bytes());
1864        expect.extend_from_slice(pod_bytes_of(&mint_transfer_fee));
1865        assert_eq!(expect, buffer);
1866
1867        // fail to init one more extension that does not fit
1868        let mut state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap();
1869        assert_eq!(
1870            state.init_extension::<MintPaddingTest>(true),
1871            Err(ProgramError::InvalidAccountData),
1872        );
1873    }
1874
1875    #[test]
1876    fn mint_extension_any_order() {
1877        let mint_size = ExtensionType::try_calculate_account_len::<PodMint>(&[
1878            ExtensionType::MintCloseAuthority,
1879            ExtensionType::TransferFeeConfig,
1880        ])
1881        .unwrap();
1882        let mut buffer = vec![0; mint_size];
1883
1884        let mut state =
1885            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
1886        // write extensions
1887        let close_authority =
1888            OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([1; 32]))).unwrap();
1889        let extension = state.init_extension::<MintCloseAuthority>(true).unwrap();
1890        extension.close_authority = close_authority;
1891
1892        let mint_transfer_fee = test_transfer_fee_config();
1893        let extension = state.init_extension::<TransferFeeConfig>(true).unwrap();
1894        extension.transfer_fee_config_authority = mint_transfer_fee.transfer_fee_config_authority;
1895        extension.withdraw_withheld_authority = mint_transfer_fee.withdraw_withheld_authority;
1896        extension.withheld_amount = mint_transfer_fee.withheld_amount;
1897        extension.older_transfer_fee = mint_transfer_fee.older_transfer_fee;
1898        extension.newer_transfer_fee = mint_transfer_fee.newer_transfer_fee;
1899
1900        assert_eq!(
1901            &state.get_extension_types().unwrap(),
1902            &[
1903                ExtensionType::MintCloseAuthority,
1904                ExtensionType::TransferFeeConfig
1905            ]
1906        );
1907
1908        // write base mint
1909        let mut state =
1910            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
1911        *state.base = TEST_POD_MINT;
1912        state.init_account_type().unwrap();
1913
1914        let mut other_buffer = vec![0; mint_size];
1915        let mut state =
1916            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut other_buffer).unwrap();
1917
1918        // write base mint
1919        *state.base = TEST_POD_MINT;
1920        state.init_account_type().unwrap();
1921
1922        // write extensions in a different order
1923        let mint_transfer_fee = test_transfer_fee_config();
1924        let extension = state.init_extension::<TransferFeeConfig>(true).unwrap();
1925        extension.transfer_fee_config_authority = mint_transfer_fee.transfer_fee_config_authority;
1926        extension.withdraw_withheld_authority = mint_transfer_fee.withdraw_withheld_authority;
1927        extension.withheld_amount = mint_transfer_fee.withheld_amount;
1928        extension.older_transfer_fee = mint_transfer_fee.older_transfer_fee;
1929        extension.newer_transfer_fee = mint_transfer_fee.newer_transfer_fee;
1930
1931        let close_authority =
1932            OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([1; 32]))).unwrap();
1933        let extension = state.init_extension::<MintCloseAuthority>(true).unwrap();
1934        extension.close_authority = close_authority;
1935
1936        assert_eq!(
1937            &state.get_extension_types().unwrap(),
1938            &[
1939                ExtensionType::TransferFeeConfig,
1940                ExtensionType::MintCloseAuthority
1941            ]
1942        );
1943
1944        // buffers are NOT the same because written in a different order
1945        assert_ne!(buffer, other_buffer);
1946        let state = PodStateWithExtensions::<PodMint>::unpack(&buffer).unwrap();
1947        let other_state = PodStateWithExtensions::<PodMint>::unpack(&other_buffer).unwrap();
1948
1949        // BUT mint and extensions are the same
1950        assert_eq!(
1951            state.get_extension::<TransferFeeConfig>().unwrap(),
1952            other_state.get_extension::<TransferFeeConfig>().unwrap()
1953        );
1954        assert_eq!(
1955            state.get_extension::<MintCloseAuthority>().unwrap(),
1956            other_state.get_extension::<MintCloseAuthority>().unwrap()
1957        );
1958        assert_eq!(state.base, other_state.base);
1959    }
1960
1961    #[test]
1962    fn mint_with_multisig_len() {
1963        let mut buffer = vec![0; Multisig::LEN];
1964        assert_eq!(
1965            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer),
1966            Err(ProgramError::InvalidAccountData),
1967        );
1968        let mint_size =
1969            ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::MintPaddingTest])
1970                .unwrap();
1971        assert_eq!(mint_size, Multisig::LEN + size_of::<ExtensionType>());
1972        let mut buffer = vec![0; mint_size];
1973
1974        // write base mint
1975        let mut state =
1976            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
1977        *state.base = TEST_POD_MINT;
1978        state.init_account_type().unwrap();
1979
1980        // write padding
1981        let extension = state.init_extension::<MintPaddingTest>(true).unwrap();
1982        extension.padding1 = [1; 128];
1983        extension.padding2 = [1; 48];
1984        extension.padding3 = [1; 9];
1985
1986        assert_eq!(
1987            &state.get_extension_types().unwrap(),
1988            &[ExtensionType::MintPaddingTest]
1989        );
1990
1991        // check raw buffer
1992        let mut expect = TEST_MINT_SLICE.to_vec();
1993        expect.extend_from_slice(&[0; BASE_ACCOUNT_LENGTH - PodMint::SIZE_OF]); // padding
1994        expect.push(AccountType::Mint.into());
1995        expect.extend_from_slice(&(ExtensionType::MintPaddingTest as u16).to_le_bytes());
1996        expect.extend_from_slice(&(pod_get_packed_len::<MintPaddingTest>() as u16).to_le_bytes());
1997        expect.extend_from_slice(&vec![1; pod_get_packed_len::<MintPaddingTest>()]);
1998        expect.extend_from_slice(&(ExtensionType::Uninitialized as u16).to_le_bytes());
1999        assert_eq!(expect, buffer);
2000    }
2001
2002    #[test]
2003    fn account_with_extension_pack_unpack() {
2004        let account_size = ExtensionType::try_calculate_account_len::<PodAccount>(&[
2005            ExtensionType::TransferFeeAmount,
2006        ])
2007        .unwrap();
2008        let mut buffer = vec![0; account_size];
2009
2010        // fail unpack
2011        assert_eq!(
2012            PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer),
2013            Err(ProgramError::UninitializedAccount),
2014        );
2015
2016        let mut state =
2017            PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer).unwrap();
2018        // fail init mint extension
2019        assert_eq!(
2020            state.init_extension::<TransferFeeConfig>(true),
2021            Err(ProgramError::InvalidAccountData),
2022        );
2023        // success write extension
2024        let withheld_amount = PodU64::from(u64::MAX);
2025        let extension = state.init_extension::<TransferFeeAmount>(true).unwrap();
2026        extension.withheld_amount = withheld_amount;
2027
2028        assert_eq!(
2029            &state.get_extension_types().unwrap(),
2030            &[ExtensionType::TransferFeeAmount]
2031        );
2032
2033        // fail unpack again, still no base data
2034        assert_eq!(
2035            PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer.clone()),
2036            Err(ProgramError::UninitializedAccount),
2037        );
2038
2039        // write base account
2040        let mut state =
2041            PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer).unwrap();
2042        *state.base = TEST_POD_ACCOUNT;
2043        state.init_account_type().unwrap();
2044        let base = *state.base;
2045
2046        // check raw buffer
2047        let mut expect = TEST_ACCOUNT_SLICE.to_vec();
2048        expect.push(AccountType::Account.into());
2049        expect.extend_from_slice(&(ExtensionType::TransferFeeAmount as u16).to_le_bytes());
2050        expect.extend_from_slice(&(pod_get_packed_len::<TransferFeeAmount>() as u16).to_le_bytes());
2051        expect.extend_from_slice(&u64::from(withheld_amount).to_le_bytes());
2052        assert_eq!(expect, buffer);
2053
2054        // check unpacking
2055        let mut state = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap();
2056        assert_eq!(state.base, &base);
2057        assert_eq!(
2058            &state.get_extension_types().unwrap(),
2059            &[ExtensionType::TransferFeeAmount]
2060        );
2061
2062        // update base
2063        *state.base = TEST_POD_ACCOUNT;
2064        state.base.amount = (u64::from(state.base.amount) + 100).into();
2065
2066        // check unpacking
2067        let unpacked_extension = state.get_extension_mut::<TransferFeeAmount>().unwrap();
2068        assert_eq!(*unpacked_extension, TransferFeeAmount { withheld_amount });
2069
2070        // update extension
2071        let withheld_amount = PodU64::from(u32::MAX as u64);
2072        unpacked_extension.withheld_amount = withheld_amount;
2073
2074        // check updates are propagated
2075        let base = *state.base;
2076        let state = PodStateWithExtensions::<PodAccount>::unpack(&buffer).unwrap();
2077        assert_eq!(state.base, &base);
2078        let unpacked_extension = state.get_extension::<TransferFeeAmount>().unwrap();
2079        assert_eq!(*unpacked_extension, TransferFeeAmount { withheld_amount });
2080
2081        // check raw buffer
2082        let mut expect = vec![];
2083        expect.extend_from_slice(pod_bytes_of(&base));
2084        expect.push(AccountType::Account.into());
2085        expect.extend_from_slice(&(ExtensionType::TransferFeeAmount as u16).to_le_bytes());
2086        expect.extend_from_slice(&(pod_get_packed_len::<TransferFeeAmount>() as u16).to_le_bytes());
2087        expect.extend_from_slice(&u64::from(withheld_amount).to_le_bytes());
2088        assert_eq!(expect, buffer);
2089
2090        // fail unpack as a mint
2091        assert_eq!(
2092            PodStateWithExtensions::<PodMint>::unpack(&buffer),
2093            Err(ProgramError::InvalidAccountData),
2094        );
2095    }
2096
2097    #[test]
2098    fn account_with_multisig_len() {
2099        let mut buffer = vec![0; Multisig::LEN];
2100        assert_eq!(
2101            PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer),
2102            Err(ProgramError::InvalidAccountData),
2103        );
2104        let account_size = ExtensionType::try_calculate_account_len::<PodAccount>(&[
2105            ExtensionType::AccountPaddingTest,
2106        ])
2107        .unwrap();
2108        assert_eq!(account_size, Multisig::LEN + size_of::<ExtensionType>());
2109        let mut buffer = vec![0; account_size];
2110
2111        // write base account
2112        let mut state =
2113            PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer).unwrap();
2114        *state.base = TEST_POD_ACCOUNT;
2115        state.init_account_type().unwrap();
2116
2117        // write padding
2118        let extension = state.init_extension::<AccountPaddingTest>(true).unwrap();
2119        extension.0.padding1 = [2; 128];
2120        extension.0.padding2 = [2; 48];
2121        extension.0.padding3 = [2; 9];
2122
2123        assert_eq!(
2124            &state.get_extension_types().unwrap(),
2125            &[ExtensionType::AccountPaddingTest]
2126        );
2127
2128        // check raw buffer
2129        let mut expect = TEST_ACCOUNT_SLICE.to_vec();
2130        expect.push(AccountType::Account.into());
2131        expect.extend_from_slice(&(ExtensionType::AccountPaddingTest as u16).to_le_bytes());
2132        expect
2133            .extend_from_slice(&(pod_get_packed_len::<AccountPaddingTest>() as u16).to_le_bytes());
2134        expect.extend_from_slice(&vec![2; pod_get_packed_len::<AccountPaddingTest>()]);
2135        expect.extend_from_slice(&(ExtensionType::Uninitialized as u16).to_le_bytes());
2136        assert_eq!(expect, buffer);
2137    }
2138
2139    #[test]
2140    fn test_set_account_type() {
2141        // account with buffer big enough for AccountType and Extension
2142        let mut buffer = TEST_ACCOUNT_SLICE.to_vec();
2143        let needed_len = ExtensionType::try_calculate_account_len::<PodAccount>(&[
2144            ExtensionType::ImmutableOwner,
2145        ])
2146        .unwrap()
2147            - buffer.len();
2148        buffer.append(&mut vec![0; needed_len]);
2149        let err = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap_err();
2150        assert_eq!(err, ProgramError::InvalidAccountData);
2151        set_account_type::<PodAccount>(&mut buffer).unwrap();
2152        // unpack is viable after manual set_account_type
2153        let mut state = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap();
2154        assert_eq!(state.base, &TEST_POD_ACCOUNT);
2155        assert_eq!(state.account_type[0], AccountType::Account as u8);
2156        state.init_extension::<ImmutableOwner>(true).unwrap(); // just confirming initialization works
2157
2158        // account with buffer big enough for AccountType only
2159        let mut buffer = TEST_ACCOUNT_SLICE.to_vec();
2160        buffer.append(&mut vec![0; 2]);
2161        let err = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap_err();
2162        assert_eq!(err, ProgramError::InvalidAccountData);
2163        set_account_type::<PodAccount>(&mut buffer).unwrap();
2164        // unpack is viable after manual set_account_type
2165        let state = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap();
2166        assert_eq!(state.base, &TEST_POD_ACCOUNT);
2167        assert_eq!(state.account_type[0], AccountType::Account as u8);
2168
2169        // account with AccountType already set => noop
2170        let mut buffer = TEST_ACCOUNT_SLICE.to_vec();
2171        buffer.append(&mut vec![2, 0]);
2172        let _ = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap();
2173        set_account_type::<PodAccount>(&mut buffer).unwrap();
2174        let state = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap();
2175        assert_eq!(state.base, &TEST_POD_ACCOUNT);
2176        assert_eq!(state.account_type[0], AccountType::Account as u8);
2177
2178        // account with wrong AccountType fails
2179        let mut buffer = TEST_ACCOUNT_SLICE.to_vec();
2180        buffer.append(&mut vec![1, 0]);
2181        let err = PodStateWithExtensionsMut::<PodAccount>::unpack(&mut buffer).unwrap_err();
2182        assert_eq!(err, ProgramError::InvalidAccountData);
2183        let err = set_account_type::<PodAccount>(&mut buffer).unwrap_err();
2184        assert_eq!(err, ProgramError::InvalidAccountData);
2185
2186        // mint with buffer big enough for AccountType and Extension
2187        let mut buffer = TEST_MINT_SLICE.to_vec();
2188        let needed_len = ExtensionType::try_calculate_account_len::<PodMint>(&[
2189            ExtensionType::MintCloseAuthority,
2190        ])
2191        .unwrap()
2192            - buffer.len();
2193        buffer.append(&mut vec![0; needed_len]);
2194        let err = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap_err();
2195        assert_eq!(err, ProgramError::InvalidAccountData);
2196        set_account_type::<PodMint>(&mut buffer).unwrap();
2197        // unpack is viable after manual set_account_type
2198        let mut state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap();
2199        assert_eq!(state.base, &TEST_POD_MINT);
2200        assert_eq!(state.account_type[0], AccountType::Mint as u8);
2201        state.init_extension::<MintCloseAuthority>(true).unwrap();
2202
2203        // mint with buffer big enough for AccountType only
2204        let mut buffer = TEST_MINT_SLICE.to_vec();
2205        buffer.append(&mut vec![0; PodAccount::SIZE_OF - PodMint::SIZE_OF]);
2206        buffer.append(&mut vec![0; 2]);
2207        let err = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap_err();
2208        assert_eq!(err, ProgramError::InvalidAccountData);
2209        set_account_type::<PodMint>(&mut buffer).unwrap();
2210        // unpack is viable after manual set_account_type
2211        let state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap();
2212        assert_eq!(state.base, &TEST_POD_MINT);
2213        assert_eq!(state.account_type[0], AccountType::Mint as u8);
2214
2215        // mint with AccountType already set => noop
2216        let mut buffer = TEST_MINT_SLICE.to_vec();
2217        buffer.append(&mut vec![0; PodAccount::SIZE_OF - PodMint::SIZE_OF]);
2218        buffer.append(&mut vec![1, 0]);
2219        set_account_type::<PodMint>(&mut buffer).unwrap();
2220        let state = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap();
2221        assert_eq!(state.base, &TEST_POD_MINT);
2222        assert_eq!(state.account_type[0], AccountType::Mint as u8);
2223
2224        // mint with wrong AccountType fails
2225        let mut buffer = TEST_MINT_SLICE.to_vec();
2226        buffer.append(&mut vec![0; PodAccount::SIZE_OF - PodMint::SIZE_OF]);
2227        buffer.append(&mut vec![2, 0]);
2228        let err = PodStateWithExtensionsMut::<PodMint>::unpack(&mut buffer).unwrap_err();
2229        assert_eq!(err, ProgramError::InvalidAccountData);
2230        let err = set_account_type::<PodMint>(&mut buffer).unwrap_err();
2231        assert_eq!(err, ProgramError::InvalidAccountData);
2232    }
2233
2234    #[test]
2235    fn test_set_account_type_wrongly() {
2236        // try to set PodAccount account_type to PodMint
2237        let mut buffer = TEST_ACCOUNT_SLICE.to_vec();
2238        buffer.append(&mut vec![0; 2]);
2239        let err = set_account_type::<PodMint>(&mut buffer).unwrap_err();
2240        assert_eq!(err, ProgramError::InvalidAccountData);
2241
2242        // try to set PodMint account_type to PodAccount
2243        let mut buffer = TEST_MINT_SLICE.to_vec();
2244        buffer.append(&mut vec![0; PodAccount::SIZE_OF - PodMint::SIZE_OF]);
2245        buffer.append(&mut vec![0; 2]);
2246        let err = set_account_type::<PodAccount>(&mut buffer).unwrap_err();
2247        assert_eq!(err, ProgramError::InvalidAccountData);
2248    }
2249
2250    #[test]
2251    fn test_get_required_init_account_extensions() {
2252        // Some mint extensions with no required account extensions
2253        let mint_extensions = vec![
2254            ExtensionType::MintCloseAuthority,
2255            ExtensionType::Uninitialized,
2256        ];
2257        assert_eq!(
2258            ExtensionType::get_required_init_account_extensions(&mint_extensions),
2259            vec![]
2260        );
2261
2262        // One mint extension with required account extension, one without
2263        let mint_extensions = vec![
2264            ExtensionType::TransferFeeConfig,
2265            ExtensionType::MintCloseAuthority,
2266        ];
2267        assert_eq!(
2268            ExtensionType::get_required_init_account_extensions(&mint_extensions),
2269            vec![ExtensionType::TransferFeeAmount]
2270        );
2271
2272        // Some mint extensions both with required account extensions
2273        let mint_extensions = vec![
2274            ExtensionType::TransferFeeConfig,
2275            ExtensionType::MintPaddingTest,
2276        ];
2277        assert_eq!(
2278            ExtensionType::get_required_init_account_extensions(&mint_extensions),
2279            vec![
2280                ExtensionType::TransferFeeAmount,
2281                ExtensionType::AccountPaddingTest
2282            ]
2283        );
2284
2285        // Demonstrate that method does not dedupe inputs or outputs
2286        let mint_extensions = vec![
2287            ExtensionType::TransferFeeConfig,
2288            ExtensionType::TransferFeeConfig,
2289        ];
2290        assert_eq!(
2291            ExtensionType::get_required_init_account_extensions(&mint_extensions),
2292            vec![
2293                ExtensionType::TransferFeeAmount,
2294                ExtensionType::TransferFeeAmount
2295            ]
2296        );
2297    }
2298
2299    #[test]
2300    fn mint_without_extensions() {
2301        let space = ExtensionType::try_calculate_account_len::<PodMint>(&[]).unwrap();
2302        let mut buffer = vec![0; space];
2303        assert_eq!(
2304            PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer),
2305            Err(ProgramError::InvalidAccountData),
2306        );
2307
2308        // write base account
2309        let mut state =
2310            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2311        *state.base = TEST_POD_MINT;
2312        state.init_account_type().unwrap();
2313
2314        // fail init extension
2315        assert_eq!(
2316            state.init_extension::<TransferFeeConfig>(true),
2317            Err(ProgramError::InvalidAccountData),
2318        );
2319
2320        assert_eq!(TEST_MINT_SLICE, buffer);
2321    }
2322
2323    #[test]
2324    fn test_init_nonzero_default() {
2325        let mint_size =
2326            ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::MintPaddingTest])
2327                .unwrap();
2328        let mut buffer = vec![0; mint_size];
2329        let mut state =
2330            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2331        *state.base = TEST_POD_MINT;
2332        state.init_account_type().unwrap();
2333        let extension = state.init_extension::<MintPaddingTest>(true).unwrap();
2334        assert_eq!(extension.padding1, [1; 128]);
2335        assert_eq!(extension.padding2, [2; 48]);
2336        assert_eq!(extension.padding3, [3; 9]);
2337    }
2338
2339    #[test]
2340    fn test_init_buffer_too_small() {
2341        let mint_size = ExtensionType::try_calculate_account_len::<PodMint>(&[
2342            ExtensionType::MintCloseAuthority,
2343        ])
2344        .unwrap();
2345        let mut buffer = vec![0; mint_size - 1];
2346        let mut state =
2347            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2348        let err = state
2349            .init_extension::<MintCloseAuthority>(true)
2350            .unwrap_err();
2351        assert_eq!(err, ProgramError::InvalidAccountData);
2352
2353        state.tlv_data[0] = 3;
2354        state.tlv_data[2] = 32;
2355        let err = state.get_extension_mut::<MintCloseAuthority>().unwrap_err();
2356        assert_eq!(err, ProgramError::InvalidAccountData);
2357
2358        let mut buffer = vec![0; PodMint::SIZE_OF + 2];
2359        let err =
2360            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap_err();
2361        assert_eq!(err, ProgramError::InvalidAccountData);
2362
2363        // OK since there are two bytes for the type, which is `Uninitialized`
2364        let mut buffer = vec![0; BASE_ACCOUNT_LENGTH + 3];
2365        let mut state =
2366            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2367        let err = state.get_extension_mut::<MintCloseAuthority>().unwrap_err();
2368        assert_eq!(err, ProgramError::InvalidAccountData);
2369
2370        assert_eq!(state.get_extension_types().unwrap(), vec![]);
2371
2372        // OK, there aren't two bytes for the type, but that's fine
2373        let mut buffer = vec![0; BASE_ACCOUNT_LENGTH + 2];
2374        let state =
2375            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2376        assert_eq!(state.get_extension_types().unwrap(), []);
2377    }
2378
2379    #[test]
2380    fn test_extension_with_no_data() {
2381        let account_size = ExtensionType::try_calculate_account_len::<PodAccount>(&[
2382            ExtensionType::ImmutableOwner,
2383        ])
2384        .unwrap();
2385        let mut buffer = vec![0; account_size];
2386        let mut state =
2387            PodStateWithExtensionsMut::<PodAccount>::unpack_uninitialized(&mut buffer).unwrap();
2388        *state.base = TEST_POD_ACCOUNT;
2389        state.init_account_type().unwrap();
2390
2391        let err = state.get_extension::<ImmutableOwner>().unwrap_err();
2392        assert_eq!(
2393            err,
2394            ProgramError::Custom(TokenError::ExtensionNotFound as u32)
2395        );
2396
2397        state.init_extension::<ImmutableOwner>(true).unwrap();
2398        assert_eq!(
2399            get_first_extension_type(state.tlv_data).unwrap(),
2400            Some(ExtensionType::ImmutableOwner)
2401        );
2402        assert_eq!(
2403            get_tlv_data_info(state.tlv_data).unwrap(),
2404            TlvDataInfo {
2405                extension_types: vec![ExtensionType::ImmutableOwner],
2406                used_len: add_type_and_length_to_len(0)
2407            }
2408        );
2409    }
2410
2411    #[test]
2412    fn fail_account_len_with_metadata() {
2413        assert_eq!(
2414            ExtensionType::try_calculate_account_len::<PodMint>(&[
2415                ExtensionType::MintCloseAuthority,
2416                ExtensionType::VariableLenMintTest,
2417                ExtensionType::TransferFeeConfig,
2418            ])
2419            .unwrap_err(),
2420            ProgramError::InvalidArgument
2421        );
2422    }
2423
2424    #[test]
2425    fn alloc() {
2426        let variable_len = VariableLenMintTest { data: vec![1] };
2427        let alloc_size = variable_len.get_packed_len().unwrap();
2428        let account_size =
2429            BASE_ACCOUNT_LENGTH + size_of::<AccountType>() + add_type_and_length_to_len(alloc_size);
2430        let mut buffer = vec![0; account_size];
2431        let mut state =
2432            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2433        state
2434            .init_variable_len_extension(&variable_len, false)
2435            .unwrap();
2436
2437        // can't double alloc
2438        assert_eq!(
2439            state
2440                .init_variable_len_extension(&variable_len, false)
2441                .unwrap_err(),
2442            TokenError::ExtensionAlreadyInitialized.into()
2443        );
2444
2445        // unless overwrite is set
2446        state
2447            .init_variable_len_extension(&variable_len, true)
2448            .unwrap();
2449
2450        // can't change the size during overwrite though
2451        assert_eq!(
2452            state
2453                .init_variable_len_extension(&VariableLenMintTest { data: vec![] }, true)
2454                .unwrap_err(),
2455            TokenError::InvalidLengthForAlloc.into()
2456        );
2457
2458        // try to write too far, fail earlier
2459        assert_eq!(
2460            state
2461                .init_variable_len_extension(&VariableLenMintTest { data: vec![1, 2] }, true)
2462                .unwrap_err(),
2463            ProgramError::InvalidAccountData
2464        );
2465    }
2466
2467    #[test]
2468    fn realloc() {
2469        let small_variable_len = VariableLenMintTest {
2470            data: vec![1, 2, 3],
2471        };
2472        let base_variable_len = VariableLenMintTest {
2473            data: vec![1, 2, 3, 4],
2474        };
2475        let big_variable_len = VariableLenMintTest {
2476            data: vec![1, 2, 3, 4, 5],
2477        };
2478        let too_big_variable_len = VariableLenMintTest {
2479            data: vec![1, 2, 3, 4, 5, 6],
2480        };
2481        let account_size =
2482            ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::MetadataPointer])
2483                .unwrap()
2484                + add_type_and_length_to_len(big_variable_len.get_packed_len().unwrap());
2485        let mut buffer = vec![0; account_size];
2486        let mut state =
2487            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2488
2489        // alloc both types
2490        state
2491            .init_variable_len_extension(&base_variable_len, false)
2492            .unwrap();
2493        let max_pubkey =
2494            OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([255; 32]))).unwrap();
2495        let extension = state.init_extension::<MetadataPointer>(false).unwrap();
2496        extension.authority = max_pubkey;
2497        extension.metadata_address = max_pubkey;
2498
2499        // realloc first entry to larger
2500        state
2501            .realloc_variable_len_extension(&big_variable_len)
2502            .unwrap();
2503        let extension = state
2504            .get_variable_len_extension::<VariableLenMintTest>()
2505            .unwrap();
2506        assert_eq!(extension, big_variable_len);
2507        let extension = state.get_extension::<MetadataPointer>().unwrap();
2508        assert_eq!(extension.authority, max_pubkey);
2509        assert_eq!(extension.metadata_address, max_pubkey);
2510
2511        // realloc to smaller
2512        state
2513            .realloc_variable_len_extension(&small_variable_len)
2514            .unwrap();
2515        let extension = state
2516            .get_variable_len_extension::<VariableLenMintTest>()
2517            .unwrap();
2518        assert_eq!(extension, small_variable_len);
2519        let extension = state.get_extension::<MetadataPointer>().unwrap();
2520        assert_eq!(extension.authority, max_pubkey);
2521        assert_eq!(extension.metadata_address, max_pubkey);
2522        let diff = big_variable_len.get_packed_len().unwrap()
2523            - small_variable_len.get_packed_len().unwrap();
2524        assert_eq!(&buffer[account_size - diff..account_size], vec![0; diff]);
2525
2526        // unpack again since we dropped the last `state`
2527        let mut state =
2528            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2529        // realloc too much, fails
2530        assert_eq!(
2531            state
2532                .realloc_variable_len_extension(&too_big_variable_len)
2533                .unwrap_err(),
2534            ProgramError::InvalidAccountData,
2535        );
2536    }
2537
2538    #[test]
2539    fn account_len() {
2540        let small_variable_len = VariableLenMintTest {
2541            data: vec![20, 30, 40],
2542        };
2543        let variable_len = VariableLenMintTest {
2544            data: vec![20, 30, 40, 50],
2545        };
2546        let big_variable_len = VariableLenMintTest {
2547            data: vec![20, 30, 40, 50, 60],
2548        };
2549        let value_len = variable_len.get_packed_len().unwrap();
2550        let account_size =
2551            BASE_ACCOUNT_LENGTH + size_of::<AccountType>() + add_type_and_length_to_len(value_len);
2552        let mut buffer = vec![0; account_size];
2553        let mut state =
2554            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2555
2556        // With a new extension, new length must include padding, 1 byte for
2557        // account type, 2 bytes for type, 2 for length
2558        let current_len = state.try_get_account_len().unwrap();
2559        assert_eq!(current_len, PodMint::SIZE_OF);
2560        let new_len = state
2561            .try_get_new_account_len_for_variable_len_extension::<VariableLenMintTest>(
2562                &variable_len,
2563            )
2564            .unwrap();
2565        assert_eq!(
2566            new_len,
2567            BASE_ACCOUNT_AND_TYPE_LENGTH.saturating_add(add_type_and_length_to_len(value_len))
2568        );
2569
2570        state
2571            .init_variable_len_extension::<VariableLenMintTest>(&variable_len, false)
2572            .unwrap();
2573        let current_len = state.try_get_account_len().unwrap();
2574        assert_eq!(current_len, new_len);
2575
2576        // Reduce the extension size
2577        let new_len = state
2578            .try_get_new_account_len_for_variable_len_extension::<VariableLenMintTest>(
2579                &small_variable_len,
2580            )
2581            .unwrap();
2582        assert_eq!(current_len.checked_sub(new_len).unwrap(), 1);
2583
2584        // Increase the extension size
2585        let new_len = state
2586            .try_get_new_account_len_for_variable_len_extension::<VariableLenMintTest>(
2587                &big_variable_len,
2588            )
2589            .unwrap();
2590        assert_eq!(new_len.checked_sub(current_len).unwrap(), 1);
2591
2592        // Maintain the extension size
2593        let new_len = state
2594            .try_get_new_account_len_for_variable_len_extension::<VariableLenMintTest>(
2595                &variable_len,
2596            )
2597            .unwrap();
2598        assert_eq!(new_len, current_len);
2599    }
2600
2601    /// Test helper for mimicking the data layout an on-chain `AccountInfo`,
2602    /// which permits "reallocs" as the Solana runtime does it
2603    struct MiralandAccountData {
2604        data: Vec<u8>,
2605        lamports: u64,
2606        owner: Pubkey,
2607    }
2608    impl MiralandAccountData {
2609        /// Create a new fake solana account data. The underlying vector is
2610        /// overallocated to mimic the runtime
2611        fn new(account_data: &[u8]) -> Self {
2612            let mut data = vec![];
2613            data.extend_from_slice(&(account_data.len() as u64).to_le_bytes());
2614            data.extend_from_slice(account_data);
2615            data.extend_from_slice(&[0; MAX_PERMITTED_DATA_INCREASE]);
2616            Self {
2617                data,
2618                lamports: 10,
2619                owner: Pubkey::new_unique(),
2620            }
2621        }
2622
2623        /// Data lops off the first 8 bytes, since those store the size of the
2624        /// account for the Miraland runtime
2625        fn data(&self) -> &[u8] {
2626            let start = size_of::<u64>();
2627            let len = self.len();
2628            &self.data[start..start + len]
2629        }
2630
2631        /// Gets the runtime length of the account data
2632        fn len(&self) -> usize {
2633            self.data
2634                .get(..size_of::<u64>())
2635                .and_then(|slice| slice.try_into().ok())
2636                .map(u64::from_le_bytes)
2637                .unwrap() as usize
2638        }
2639    }
2640    impl GetAccount for MiralandAccountData {
2641        fn get(&mut self) -> (&mut u64, &mut [u8], &Pubkey, bool, Epoch) {
2642            // need to pull out the data here to avoid a double-mutable borrow
2643            let start = size_of::<u64>();
2644            let len = self.len();
2645            (
2646                &mut self.lamports,
2647                &mut self.data[start..start + len],
2648                &self.owner,
2649                false,
2650                Epoch::default(),
2651            )
2652        }
2653    }
2654
2655    #[test]
2656    fn alloc_new_fixed_len_tlv_in_account_info_from_base_size() {
2657        let fixed_len = FixedLenMintTest {
2658            data: [1, 2, 3, 4, 5, 6, 7, 8],
2659        };
2660        let value_len = pod_get_packed_len::<FixedLenMintTest>();
2661        let base_account_size = PodMint::SIZE_OF;
2662        let mut buffer = vec![0; base_account_size];
2663        let state =
2664            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2665        *state.base = TEST_POD_MINT;
2666
2667        let mut data = MiralandAccountData::new(&buffer);
2668        let key = Pubkey::new_unique();
2669        let account_info = (&key, &mut data).into_account_info();
2670
2671        alloc_and_serialize::<PodMint, _>(&account_info, &fixed_len, false).unwrap();
2672        let new_account_len = BASE_ACCOUNT_AND_TYPE_LENGTH + add_type_and_length_to_len(value_len);
2673        assert_eq!(data.len(), new_account_len);
2674        let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2675        assert_eq!(
2676            state.get_extension::<FixedLenMintTest>().unwrap(),
2677            &fixed_len,
2678        );
2679
2680        // alloc again succeeds with "overwrite"
2681        let account_info = (&key, &mut data).into_account_info();
2682        alloc_and_serialize::<PodMint, _>(&account_info, &fixed_len, true).unwrap();
2683
2684        // alloc again fails without "overwrite"
2685        let account_info = (&key, &mut data).into_account_info();
2686        assert_eq!(
2687            alloc_and_serialize::<PodMint, _>(&account_info, &fixed_len, false).unwrap_err(),
2688            TokenError::ExtensionAlreadyInitialized.into()
2689        );
2690    }
2691
2692    #[test]
2693    fn alloc_new_variable_len_tlv_in_account_info_from_base_size() {
2694        let variable_len = VariableLenMintTest { data: vec![20, 99] };
2695        let value_len = variable_len.get_packed_len().unwrap();
2696        let base_account_size = PodMint::SIZE_OF;
2697        let mut buffer = vec![0; base_account_size];
2698        let state =
2699            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2700        *state.base = TEST_POD_MINT;
2701
2702        let mut data = MiralandAccountData::new(&buffer);
2703        let key = Pubkey::new_unique();
2704        let account_info = (&key, &mut data).into_account_info();
2705
2706        alloc_and_serialize_variable_len_extension::<PodMint, _>(
2707            &account_info,
2708            &variable_len,
2709            false,
2710        )
2711        .unwrap();
2712        let new_account_len = BASE_ACCOUNT_AND_TYPE_LENGTH + add_type_and_length_to_len(value_len);
2713        assert_eq!(data.len(), new_account_len);
2714        let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2715        assert_eq!(
2716            state
2717                .get_variable_len_extension::<VariableLenMintTest>()
2718                .unwrap(),
2719            variable_len
2720        );
2721
2722        // alloc again succeeds with "overwrite"
2723        let account_info = (&key, &mut data).into_account_info();
2724        alloc_and_serialize_variable_len_extension::<PodMint, _>(
2725            &account_info,
2726            &variable_len,
2727            true,
2728        )
2729        .unwrap();
2730
2731        // alloc again fails without "overwrite"
2732        let account_info = (&key, &mut data).into_account_info();
2733        assert_eq!(
2734            alloc_and_serialize_variable_len_extension::<PodMint, _>(
2735                &account_info,
2736                &variable_len,
2737                false,
2738            )
2739            .unwrap_err(),
2740            TokenError::ExtensionAlreadyInitialized.into()
2741        );
2742    }
2743
2744    #[test]
2745    fn alloc_new_fixed_len_tlv_in_account_info_from_extended_size() {
2746        let fixed_len = FixedLenMintTest {
2747            data: [1, 2, 3, 4, 5, 6, 7, 8],
2748        };
2749        let value_len = pod_get_packed_len::<FixedLenMintTest>();
2750        let account_size =
2751            ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::GroupPointer])
2752                .unwrap()
2753                + add_type_and_length_to_len(value_len);
2754        let mut buffer = vec![0; account_size];
2755        let mut state =
2756            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2757        *state.base = TEST_POD_MINT;
2758        state.init_account_type().unwrap();
2759
2760        let test_key =
2761            OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([20; 32]))).unwrap();
2762        let extension = state.init_extension::<GroupPointer>(false).unwrap();
2763        extension.authority = test_key;
2764        extension.group_address = test_key;
2765
2766        let mut data = MiralandAccountData::new(&buffer);
2767        let key = Pubkey::new_unique();
2768        let account_info = (&key, &mut data).into_account_info();
2769
2770        alloc_and_serialize::<PodMint, _>(&account_info, &fixed_len, false).unwrap();
2771        let new_account_len = BASE_ACCOUNT_AND_TYPE_LENGTH
2772            + add_type_and_length_to_len(value_len)
2773            + add_type_and_length_to_len(size_of::<GroupPointer>());
2774        assert_eq!(data.len(), new_account_len);
2775        let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2776        assert_eq!(
2777            state.get_extension::<FixedLenMintTest>().unwrap(),
2778            &fixed_len,
2779        );
2780        let extension = state.get_extension::<GroupPointer>().unwrap();
2781        assert_eq!(extension.authority, test_key);
2782        assert_eq!(extension.group_address, test_key);
2783
2784        // alloc again succeeds with "overwrite"
2785        let account_info = (&key, &mut data).into_account_info();
2786        alloc_and_serialize::<PodMint, _>(&account_info, &fixed_len, true).unwrap();
2787
2788        // alloc again fails without "overwrite"
2789        let account_info = (&key, &mut data).into_account_info();
2790        assert_eq!(
2791            alloc_and_serialize::<PodMint, _>(&account_info, &fixed_len, false).unwrap_err(),
2792            TokenError::ExtensionAlreadyInitialized.into()
2793        );
2794    }
2795
2796    #[test]
2797    fn alloc_new_variable_len_tlv_in_account_info_from_extended_size() {
2798        let variable_len = VariableLenMintTest { data: vec![42, 6] };
2799        let value_len = variable_len.get_packed_len().unwrap();
2800        let account_size =
2801            ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::MetadataPointer])
2802                .unwrap()
2803                + add_type_and_length_to_len(value_len);
2804        let mut buffer = vec![0; account_size];
2805        let mut state =
2806            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2807        *state.base = TEST_POD_MINT;
2808        state.init_account_type().unwrap();
2809
2810        let test_key =
2811            OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([20; 32]))).unwrap();
2812        let extension = state.init_extension::<MetadataPointer>(false).unwrap();
2813        extension.authority = test_key;
2814        extension.metadata_address = test_key;
2815
2816        let mut data = MiralandAccountData::new(&buffer);
2817        let key = Pubkey::new_unique();
2818        let account_info = (&key, &mut data).into_account_info();
2819
2820        alloc_and_serialize_variable_len_extension::<PodMint, _>(
2821            &account_info,
2822            &variable_len,
2823            false,
2824        )
2825        .unwrap();
2826        let new_account_len = BASE_ACCOUNT_AND_TYPE_LENGTH
2827            + add_type_and_length_to_len(value_len)
2828            + add_type_and_length_to_len(size_of::<MetadataPointer>());
2829        assert_eq!(data.len(), new_account_len);
2830        let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2831        assert_eq!(
2832            state
2833                .get_variable_len_extension::<VariableLenMintTest>()
2834                .unwrap(),
2835            variable_len
2836        );
2837        let extension = state.get_extension::<MetadataPointer>().unwrap();
2838        assert_eq!(extension.authority, test_key);
2839        assert_eq!(extension.metadata_address, test_key);
2840
2841        // alloc again succeeds with "overwrite"
2842        let account_info = (&key, &mut data).into_account_info();
2843        alloc_and_serialize_variable_len_extension::<PodMint, _>(
2844            &account_info,
2845            &variable_len,
2846            true,
2847        )
2848        .unwrap();
2849
2850        // alloc again fails without "overwrite"
2851        let account_info = (&key, &mut data).into_account_info();
2852        assert_eq!(
2853            alloc_and_serialize_variable_len_extension::<PodMint, _>(
2854                &account_info,
2855                &variable_len,
2856                false,
2857            )
2858            .unwrap_err(),
2859            TokenError::ExtensionAlreadyInitialized.into()
2860        );
2861    }
2862
2863    #[test]
2864    fn realloc_variable_len_tlv_in_account_info() {
2865        let variable_len = VariableLenMintTest {
2866            data: vec![1, 2, 3, 4, 5],
2867        };
2868        let alloc_size = variable_len.get_packed_len().unwrap();
2869        let account_size =
2870            ExtensionType::try_calculate_account_len::<PodMint>(&[ExtensionType::MetadataPointer])
2871                .unwrap()
2872                + add_type_and_length_to_len(alloc_size);
2873        let mut buffer = vec![0; account_size];
2874        let mut state =
2875            PodStateWithExtensionsMut::<PodMint>::unpack_uninitialized(&mut buffer).unwrap();
2876        *state.base = TEST_POD_MINT;
2877        state.init_account_type().unwrap();
2878
2879        // alloc both types
2880        state
2881            .init_variable_len_extension(&variable_len, false)
2882            .unwrap();
2883        let max_pubkey =
2884            OptionalNonZeroPubkey::try_from(Some(Pubkey::new_from_array([255; 32]))).unwrap();
2885        let extension = state.init_extension::<MetadataPointer>(false).unwrap();
2886        extension.authority = max_pubkey;
2887        extension.metadata_address = max_pubkey;
2888
2889        // reallocate to smaller, make sure existing extension is fine
2890        let mut data = MiralandAccountData::new(&buffer);
2891        let key = Pubkey::new_unique();
2892        let account_info = (&key, &mut data).into_account_info();
2893        let variable_len = VariableLenMintTest { data: vec![1, 2] };
2894        alloc_and_serialize_variable_len_extension::<PodMint, _>(
2895            &account_info,
2896            &variable_len,
2897            true,
2898        )
2899        .unwrap();
2900
2901        let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2902        let extension = state.get_extension::<MetadataPointer>().unwrap();
2903        assert_eq!(extension.authority, max_pubkey);
2904        assert_eq!(extension.metadata_address, max_pubkey);
2905        let extension = state
2906            .get_variable_len_extension::<VariableLenMintTest>()
2907            .unwrap();
2908        assert_eq!(extension, variable_len);
2909        assert_eq!(data.len(), state.try_get_account_len().unwrap());
2910
2911        // reallocate to larger
2912        let account_info = (&key, &mut data).into_account_info();
2913        let variable_len = VariableLenMintTest {
2914            data: vec![1, 2, 3, 4, 5, 6, 7],
2915        };
2916        alloc_and_serialize_variable_len_extension::<PodMint, _>(
2917            &account_info,
2918            &variable_len,
2919            true,
2920        )
2921        .unwrap();
2922
2923        let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2924        let extension = state.get_extension::<MetadataPointer>().unwrap();
2925        assert_eq!(extension.authority, max_pubkey);
2926        assert_eq!(extension.metadata_address, max_pubkey);
2927        let extension = state
2928            .get_variable_len_extension::<VariableLenMintTest>()
2929            .unwrap();
2930        assert_eq!(extension, variable_len);
2931        assert_eq!(data.len(), state.try_get_account_len().unwrap());
2932
2933        // reallocate to same
2934        let account_info = (&key, &mut data).into_account_info();
2935        let variable_len = VariableLenMintTest {
2936            data: vec![7, 6, 5, 4, 3, 2, 1],
2937        };
2938        alloc_and_serialize_variable_len_extension::<PodMint, _>(
2939            &account_info,
2940            &variable_len,
2941            true,
2942        )
2943        .unwrap();
2944
2945        let state = PodStateWithExtensions::<PodMint>::unpack(data.data()).unwrap();
2946        let extension = state.get_extension::<MetadataPointer>().unwrap();
2947        assert_eq!(extension.authority, max_pubkey);
2948        assert_eq!(extension.metadata_address, max_pubkey);
2949        let extension = state
2950            .get_variable_len_extension::<VariableLenMintTest>()
2951            .unwrap();
2952        assert_eq!(extension, variable_len);
2953        assert_eq!(data.len(), state.try_get_account_len().unwrap());
2954    }
2955}