Skip to content

Instantly share code, notes, and snippets.

@FrankC01
Created October 20, 2021 10:38
Show Gist options
  • Select an option

  • Save FrankC01/b03937c5e8c74753eb552ca1e15ba8f8 to your computer and use it in GitHub Desktop.

Select an option

Save FrankC01/b03937c5e8c74753eb552ca1e15ba8f8 to your computer and use it in GitHub Desktop.

Revisions

  1. FrankC01 created this gist Oct 20, 2021.
    139 changes: 139 additions & 0 deletions main.rs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,139 @@
    // Used to map pointers into data array
    use arrayref::{array_mut_ref, array_ref, array_refs, mut_array_refs};
    use borsh::{BorshDeserialize, BorshSerialize};
    use std::iter::repeat;

    const INITIALIZED_BYTES: usize = 1;
    const VECTOR_CHUNK_LENGTH: usize = 4;
    const VECTOR_CHUNK_BYTES: usize = 5116;
    const DATA_ACCOUNT_STATE_SPACE: usize =
    INITIALIZED_BYTES + VECTOR_CHUNK_LENGTH + VECTOR_CHUNK_BYTES;

    #[derive(Debug, BorshDeserialize, BorshSerialize, Default)]
    struct FauxStructure {
    somestring: String,
    somecount: u32,
    }

    #[derive(Debug, BorshDeserialize, BorshSerialize, Default)]
    struct FauxProgram {
    initialized: bool,
    data_vec: Vec<FauxStructure>,
    }

    impl FauxProgram {
    /// Add a new FauxStructure to the vector
    fn add_struct(&mut self, mystruct: FauxStructure) {
    self.data_vec.push(mystruct);
    self.drop_first()
    }
    /// Drops the first element if there are 2 or more
    fn drop_first(&mut self) {
    // If I have more than one entry
    // remove the 0th
    if self.data_vec.len() > 2 {
    self.data_vec.remove(0);
    }
    // Do nothing
    else {
    }
    }

    /// Emulate Pack
    #[allow(clippy::ptr_offset_with_cast)]
    fn pack_into_slice(&self, dst: &mut [u8]) {
    // Setup a pointer to the overall data
    let dst = array_mut_ref![dst, 0, DATA_ACCOUNT_STATE_SPACE];
    // Convert array to three (3) reference pointers
    let (is_initialized_dst, vec_len, vec_dst) = mut_array_refs![
    dst,
    INITIALIZED_BYTES,
    VECTOR_CHUNK_LENGTH,
    VECTOR_CHUNK_BYTES
    ];

    is_initialized_dst[0] = self.initialized as u8;
    // Serialize the vector using Borsh
    let data_ser = self.data_vec.try_to_vec().unwrap();
    // Get the resulting length in bytes
    let data_len = data_ser.len();
    // Store the length (used in later unpacking/deserializing)
    vec_len[..].copy_from_slice(&(data_len as u32).to_le_bytes());
    // Store the data
    vec_dst[..data_len].copy_from_slice(&data_ser);
    }

    /// Emulate Unpack
    #[allow(clippy::ptr_offset_with_cast)]
    fn unpack_from_slice(src: &[u8]) -> Self {
    let src = array_ref![src, 0, DATA_ACCOUNT_STATE_SPACE];
    let (is_initialized_src, vec_len, vec_src) = array_refs![
    src,
    INITIALIZED_BYTES,
    VECTOR_CHUNK_LENGTH,
    VECTOR_CHUNK_BYTES
    ];
    let is_initialized = match is_initialized_src {
    [0] => false,
    [1] => true,
    _ => panic!(),
    };
    // Setup default empty vector if first use
    let mut vec_dser = Vec::<FauxStructure>::new();
    let data_length = u32::from_le_bytes(*vec_len) as usize;
    // Has data, deseriaalize to vector of structures
    if data_length > 0 {
    vec_dser = Vec::<FauxStructure>::try_from_slice(&vec_src[0..data_length]).unwrap()
    }
    // Return instance of encapsulating structure
    Self {
    initialized: is_initialized,
    data_vec: vec_dser,
    }
    }
    }
    fn main() {
    // Setup the 'emulated' account data space
    let mut faux_data: Vec<u8> = repeat(0u8).take(DATA_ACCOUNT_STATE_SPACE).collect();
    // Emulate unpacking from an accounts data area
    let mut account_state = FauxProgram::unpack_from_slice(&faux_data);
    println!("Account initial state T0 = {:?}", account_state);
    // Should always initialize the state before instruction data
    account_state.initialized = true;
    // Add 1st fake structure destined to reside in account's data space
    account_state.add_struct(FauxStructure {
    somestring: String::from("first"),
    somecount: 1u32,
    });
    println!("Account state T1 (added first) = {:?}", account_state);
    // Add 2nd fake structure destined to reside in account's data space
    account_state.add_struct(FauxStructure {
    somestring: String::from("second"),
    somecount: 2u32,
    });
    println!(
    "Account state T2 (added second and packing) = {:?}",
    account_state
    );
    // Emulate packing into account data space
    account_state.pack_into_slice(&mut faux_data);
    // Emulate unpacking from an accounts data area
    let mut account_state_next = FauxProgram::unpack_from_slice(&faux_data);
    println!(
    "Account state T3 (after unpacked) = {:?}",
    account_state_next
    );
    // Add 3rd fake structure destined to resode in account's data space
    account_state_next.add_struct(FauxStructure {
    somestring: String::from("third"),
    somecount: 3u32,
    });
    println!(
    "Account state T4 (added third and packing) = {:?}",
    account_state
    );
    // Emulate packing into account data space
    account_state_next.pack_into_slice(&mut faux_data);
    let account_state_last = FauxProgram::unpack_from_slice(&faux_data);
    println!("Account state end mock = {:?}", account_state_last);
    }