Эх сурвалжийг харах

[message-buffer 14/x] - Message buffer/zero copy fixes (#811)

* test(message-buffer): add rust integration tests

add rust-toolchain.toml to pin rust version, add integration tests, update cpi caller auth seeds

* refactor(message-buffer): remove unused test ix

* chore(message-buffer): clean up

* refactor(message-buffer): simple refactor

* test(message-buffer): refactor integration test structure

* refactor(message-buffer): rename

* fix(message-buffer): fix min size check when shrinking msg buffer

* chore(message-buffer): cleanup

* fix(message-buffer): resize borrow bug fix

* test(message-buffer): refactor test util methods into MessageBufferTestContext for less duplication

* test(message-buffer): resolve merge conflicts from repo restructure

* chore(message-buffer): delete commented out code

* feat(message-buffer): use AccountLoader for zero-copy for resize/delete & put_all

* chore(message-buffer): clean up

* style(message-buffer): clean up

* fix(message-buffer): address PR feedback

revert to old put_all impl of using bytemuck for deserializing header, update tests add back old
check

* chore(message-buffer): clean up
swimricky 2 жил өмнө
parent
commit
78d3c5c4ca

+ 0 - 1
pythnet/message_buffer/programs/message_buffer/src/instructions/create_buffer.rs

@@ -76,7 +76,6 @@ pub fn create_buffer<'info>(
         }
         loader.exit(&crate::ID)?;
     } else {
-        // FIXME: change this to be emit!(Event)
         msg!("Buffer account already initialized");
     }
 

+ 11 - 34
pythnet/message_buffer/programs/message_buffer/src/instructions/delete_buffer.rs

@@ -1,51 +1,21 @@
 use {
-    crate::{
-        state::*,
-        MessageBufferError,
-        MESSAGE,
-    },
+    crate::state::*,
     anchor_lang::prelude::*,
 };
 
 pub fn delete_buffer<'info>(
     ctx: Context<'_, '_, '_, 'info, DeleteBuffer<'info>>,
     allowed_program_auth: Pubkey,
-    base_account_key: Pubkey,
-    bump: u8,
+    _base_account_key: Pubkey,
 ) -> Result<()> {
-    let message_buffer_account_info = ctx
-        .remaining_accounts
-        .first()
-        .ok_or(MessageBufferError::MessageBufferNotProvided)?;
-
     ctx.accounts
         .whitelist
         .is_allowed_program_auth(&allowed_program_auth)?;
-
-    MessageBuffer::check_discriminator(message_buffer_account_info)?;
-
-    let expected_key = Pubkey::create_program_address(
-        &[
-            allowed_program_auth.as_ref(),
-            MESSAGE.as_bytes(),
-            base_account_key.as_ref(),
-            &[bump],
-        ],
-        &crate::ID,
-    )
-    .map_err(|_| MessageBufferError::InvalidPDA)?;
-
-    require_keys_eq!(
-        message_buffer_account_info.key(),
-        expected_key,
-        MessageBufferError::InvalidPDA
-    );
-    let loader = AccountLoader::<MessageBuffer>::try_from(message_buffer_account_info)?;
-    loader.close(ctx.accounts.admin.to_account_info())?;
     Ok(())
 }
 
 #[derive(Accounts)]
+#[instruction(allowed_program_auth: Pubkey, base_account_key: Pubkey)]
 pub struct DeleteBuffer<'info> {
     #[account(
         seeds = [b"message".as_ref(), b"whitelist".as_ref()],
@@ -57,5 +27,12 @@ pub struct DeleteBuffer<'info> {
     // Also the recipient of the lamports from closing the buffer account
     #[account(mut)]
     pub admin: Signer<'info>,
-    // remaining_account:  - [AccumulatorInput PDA]
+
+    #[account(
+    mut,
+    close = admin,
+    seeds = [allowed_program_auth.as_ref(), b"message".as_ref(), base_account_key.as_ref()],
+    bump = message_buffer.load()?.bump,
+    )]
+    pub message_buffer: AccountLoader<'info, MessageBuffer>,
 }

+ 13 - 26
pythnet/message_buffer/programs/message_buffer/src/instructions/put_all.rs

@@ -1,53 +1,40 @@
 use {
-    crate::{
-        state::*,
-        MessageBufferError,
-    },
+    crate::state::*,
     anchor_lang::prelude::*,
-    std::mem,
 };
 
 
 pub fn put_all<'info>(
     ctx: Context<'_, '_, '_, 'info, PutAll<'info>>,
-    base_account_key: Pubkey,
+    _base_account_key: Pubkey,
     messages: Vec<Vec<u8>>,
 ) -> Result<()> {
-    let cpi_caller_auth = ctx.accounts.whitelist_verifier.is_allowed()?;
-    let message_buffer_account_info = ctx
-        .remaining_accounts
-        .first()
-        .ok_or(MessageBufferError::MessageBufferNotProvided)?;
+    ctx.accounts.whitelist_verifier.is_allowed()?;
 
-    MessageBuffer::check_discriminator(message_buffer_account_info)?;
-
-    let account_data = &mut message_buffer_account_info.try_borrow_mut_data()?;
-    let header_end_index = mem::size_of::<MessageBuffer>() + 8;
+    let msg_buffer_ai = ctx.accounts.message_buffer.to_account_info();
+    let account_data = &mut msg_buffer_ai.try_borrow_mut_data()?;
+    let header_end_index = MessageBuffer::HEADER_LEN as usize;
 
     let (header_bytes, body_bytes) = account_data.split_at_mut(header_end_index);
 
     let message_buffer: &mut MessageBuffer = bytemuck::from_bytes_mut(&mut header_bytes[8..]);
 
-    message_buffer.validate(
-        message_buffer_account_info.key(),
-        cpi_caller_auth,
-        base_account_key,
-    )?;
-
     message_buffer.refresh_header();
-
     let (num_msgs, num_bytes) = message_buffer.put_all_in_buffer(body_bytes, &messages);
-
     if num_msgs != messages.len() {
         msg!("unable to fit all messages in MessageBuffer account. Wrote {}/{} messages and {} bytes", num_msgs, messages.len(), num_bytes);
     }
-
     Ok(())
 }
 
 #[derive(Accounts)]
-#[instruction( base_account_key: Pubkey)]
+#[instruction(base_account_key: Pubkey)]
 pub struct PutAll<'info> {
     pub whitelist_verifier: WhitelistVerifier<'info>,
-    // remaining_accounts:  - [AccumulatorInput PDA]
+    #[account(
+        mut,
+        seeds = [whitelist_verifier.cpi_caller_auth.key().as_ref(), b"message".as_ref(), base_account_key.as_ref()],
+        bump = message_buffer.load()?.bump,
+    )]
+    pub message_buffer:     AccountLoader<'info, MessageBuffer>,
 }

+ 24 - 88
pythnet/message_buffer/programs/message_buffer/src/instructions/resize_buffer.rs

@@ -2,112 +2,35 @@ use {
     crate::{
         state::*,
         MessageBufferError,
-        MESSAGE,
-    },
-    anchor_lang::{
-        prelude::*,
-        solana_program::entrypoint::MAX_PERMITTED_DATA_INCREASE,
-        system_program::{
-            self,
-            Transfer,
-        },
     },
+    anchor_lang::prelude::*,
 };
 
+
 pub fn resize_buffer<'info>(
     ctx: Context<'_, '_, '_, 'info, ResizeBuffer<'info>>,
     allowed_program_auth: Pubkey,
-    base_account_key: Pubkey,
-    buffer_bump: u8,
+    _base_account_key: Pubkey,
     target_size: u32,
 ) -> Result<()> {
-    let message_buffer_account_info = ctx
-        .remaining_accounts
-        .first()
-        .ok_or(MessageBufferError::MessageBufferNotProvided)?;
-
     ctx.accounts
         .whitelist
         .is_allowed_program_auth(&allowed_program_auth)?;
-    MessageBuffer::check_discriminator(message_buffer_account_info)?;
-
 
-    let target_size = target_size as usize;
-
-    let current_account_size = message_buffer_account_info.data_len();
-    let target_size_delta = target_size.saturating_sub(current_account_size);
+    let message_buffer = &ctx.accounts.message_buffer.load()?;
+    let max_end_offset = message_buffer.end_offsets.iter().max().unwrap();
+    let minimum_size = max_end_offset + message_buffer.header_len;
     require_gte!(
-        MAX_PERMITTED_DATA_INCREASE,
-        target_size_delta,
-        MessageBufferError::TargetSizeDeltaExceeded
-    );
-
-    let expected_key = Pubkey::create_program_address(
-        &[
-            allowed_program_auth.as_ref(),
-            MESSAGE.as_bytes(),
-            base_account_key.as_ref(),
-            &[buffer_bump],
-        ],
-        &crate::ID,
-    )
-    .map_err(|_| MessageBufferError::InvalidPDA)?;
-
-    require_keys_eq!(
-        message_buffer_account_info.key(),
-        expected_key,
-        MessageBufferError::InvalidPDA
+        target_size as usize,
+        minimum_size as usize,
+        MessageBufferError::MessageBufferTooSmall
     );
-
-    // allow for target_size == account_size in case Rent requirements have changed
-    // and additional lamports need to be transferred.
-    // the realloc step will be a no-op in this case.
-    if target_size >= current_account_size {
-        let target_rent = Rent::get()?.minimum_balance(target_size);
-        if message_buffer_account_info.lamports() < target_rent {
-            system_program::transfer(
-                CpiContext::new(
-                    ctx.accounts.system_program.to_account_info(),
-                    Transfer {
-                        from: ctx.accounts.admin.to_account_info(),
-                        to:   message_buffer_account_info.to_account_info(),
-                    },
-                ),
-                target_rent - message_buffer_account_info.lamports(),
-            )?;
-        }
-        message_buffer_account_info
-            .realloc(target_size, false)
-            .map_err(|_| MessageBufferError::ReallocFailed)?;
-    } else {
-        // Check that account doesn't get resized to smaller than the amount of
-        // data it is currently holding (if any)
-        {
-            let account_data = &message_buffer_account_info.try_borrow_data()?;
-            let header_end_index = std::mem::size_of::<MessageBuffer>() + 8;
-            let (header_bytes, _) = account_data.split_at(header_end_index);
-            let message_buffer: &MessageBuffer = bytemuck::from_bytes(&header_bytes[8..]);
-            let max_end_offset = message_buffer.end_offsets.iter().max().unwrap();
-            let minimum_size = max_end_offset + message_buffer.header_len;
-            require_gte!(
-                target_size,
-                minimum_size as usize,
-                MessageBufferError::MessageBufferTooSmall
-            );
-        }
-
-
-        // Not transferring excess lamports back to admin.
-        // Account will retain more lamports than necessary.
-        message_buffer_account_info.realloc(target_size, false)?;
-    }
     Ok(())
 }
 
 #[derive(Accounts)]
 #[instruction(
-    allowed_program_auth: Pubkey, base_account_key: Pubkey,
-    buffer_bump: u8, target_size: u32
+    allowed_program_auth: Pubkey, base_account_key: Pubkey, target_size: u32
 )]
 pub struct ResizeBuffer<'info> {
     #[account(
@@ -122,5 +45,18 @@ pub struct ResizeBuffer<'info> {
     pub admin: Signer<'info>,
 
     pub system_program: Program<'info, System>,
-    // remaining_accounts:  - [AccumulatorInput PDA]
+
+    /// If decreasing, Anchor will automatically check
+    /// if target_size is too small and if so,then load() will fail.
+    /// If increasing, Anchor also automatically checks if target_size delta
+    /// exceeds MAX_PERMITTED_DATA_INCREASE
+    #[account(
+        mut,
+        realloc = target_size as usize,
+        realloc::zero = false,
+        realloc::payer = admin,
+        seeds = [allowed_program_auth.as_ref(), b"message".as_ref(), base_account_key.as_ref()],
+        bump = message_buffer.load()?.bump,
+    )]
+    pub message_buffer: AccountLoader<'info, MessageBuffer>,
 }

+ 2 - 12
pythnet/message_buffer/programs/message_buffer/src/lib.rs

@@ -112,21 +112,13 @@ pub mod message_buffer {
     /// *`target_size`          -  Size to re-allocate for the
     ///                           `MessageBuffer` PDA. If increasing the size,
     ///                           max delta of current_size & target_size is 10240
-    /// *`buffer_bump`          -  Bump seed for the `MessageBuffer` PDA
     pub fn resize_buffer<'info>(
         ctx: Context<'_, '_, '_, 'info, ResizeBuffer<'info>>,
         allowed_program_auth: Pubkey,
         base_account_key: Pubkey,
-        buffer_bump: u8,
         target_size: u32,
     ) -> Result<()> {
-        instructions::resize_buffer(
-            ctx,
-            allowed_program_auth,
-            base_account_key,
-            buffer_bump,
-            target_size,
-        )
+        instructions::resize_buffer(ctx, allowed_program_auth, base_account_key, target_size)
     }
 
     /// Closes the buffer account and transfers the remaining lamports to the
@@ -138,14 +130,12 @@ pub mod message_buffer {
     /// * `base_account_key`    - Pubkey of the original account the
     ///                           `MessageBuffer` is derived from
     ///                           (e.g. pyth price account)
-    /// *`buffer_bump`          -  Bump seed for the `MessageBuffer` PDA
     pub fn delete_buffer<'info>(
         ctx: Context<'_, '_, '_, 'info, DeleteBuffer<'info>>,
         allowed_program_auth: Pubkey,
         base_account_key: Pubkey,
-        buffer_bump: u8,
     ) -> Result<()> {
-        instructions::delete_buffer(ctx, allowed_program_auth, base_account_key, buffer_bump)
+        instructions::delete_buffer(ctx, allowed_program_auth, base_account_key)
     }
 }
 

+ 17 - 47
pythnet/message_buffer/programs/message_buffer/src/state/message_buffer.rs

@@ -1,13 +1,9 @@
 use {
     crate::{
         accumulator_input_seeds,
-        instructions,
         MessageBufferError,
     },
-    anchor_lang::{
-        prelude::*,
-        Discriminator,
-    },
+    anchor_lang::prelude::*,
 };
 
 /// A MessageBuffer will have the following structure
@@ -78,6 +74,7 @@ impl MessageBuffer {
         self.end_offsets = [0u16; u8::MAX as usize];
     }
 
+
     /// `put_all` writes all the messages to the `AccumulatorInput` account
     /// and updates the `end_offsets` array.
     ///
@@ -131,28 +128,6 @@ impl MessageBuffer {
         require_keys_eq!(expected_key, key);
         Ok(())
     }
-
-    /// Verify message buffer account is initialized and has the correct discriminator.
-    ///
-    /// Note: manually checking because using anchor's `AccountLoader.load()`
-    /// will panic since the `AccountInfo.data_len()` will not match the
-    /// size of the `MessageBuffer` since the `MessageBuffer` struct does not
-    /// include the messages.
-    pub fn check_discriminator(message_buffer_account_info: &AccountInfo) -> Result<()> {
-        if instructions::is_uninitialized_account(message_buffer_account_info) {
-            return err!(MessageBufferError::MessageBufferUninitialized);
-        }
-        let data = message_buffer_account_info.try_borrow_data()?;
-        if data.len() < MessageBuffer::discriminator().len() {
-            return Err(ErrorCode::AccountDiscriminatorNotFound.into());
-        }
-
-        let disc_bytes = &data[0..8];
-        if disc_bytes != &MessageBuffer::discriminator() {
-            return Err(ErrorCode::AccountDiscriminatorMismatch.into());
-        }
-        Ok(())
-    }
 }
 
 #[cfg(test)]
@@ -222,16 +197,11 @@ mod test {
 
         let header_len = MessageBuffer::HEADER_LEN as usize;
 
-
         let (header_bytes, body_bytes) = account_info_data.split_at_mut(header_len);
         let message_buffer: &mut MessageBuffer = bytemuck::from_bytes_mut(&mut header_bytes[8..]);
 
         let (num_msgs, num_bytes) = message_buffer.put_all_in_buffer(body_bytes, &data_bytes);
 
-
-        let message_buffer: &MessageBuffer =
-            bytemuck::from_bytes(&account_info_data.as_slice()[8..header_len]);
-
         assert_eq!(num_msgs, 2);
         assert_eq!(num_bytes, 5);
 
@@ -239,6 +209,8 @@ mod test {
         assert_eq!(message_buffer.end_offsets[0], 2);
         assert_eq!(message_buffer.end_offsets[1], 5);
 
+        let message_buffer: &MessageBuffer =
+            bytemuck::from_bytes(&account_info_data.as_slice()[8..header_len]);
 
         let iter = message_buffer.end_offsets.iter().take_while(|x| **x != 0);
         let mut start = header_len;
@@ -258,6 +230,7 @@ mod test {
         }
     }
 
+
     #[test]
     fn test_put_all_exceed_max() {
         let data = vec![vec![0u8; 9_718 - 2], vec![0u8], vec![0u8; 2]];
@@ -269,20 +242,24 @@ mod test {
         let header_len = MessageBuffer::HEADER_LEN as usize;
 
         let (header_bytes, body_bytes) = account_info_data.split_at_mut(header_len);
+
         let message_buffer: &mut MessageBuffer = bytemuck::from_bytes_mut(&mut header_bytes[8..]);
 
         let (num_msgs, num_bytes) = message_buffer.put_all_in_buffer(body_bytes, &data_bytes);
 
-
-        let message_buffer: &MessageBuffer =
-            bytemuck::from_bytes(&account_info_data.as_slice()[8..header_len]);
-
         assert_eq!(num_msgs, 2);
         assert_eq!(
             num_bytes,
             data_bytes[0..2].iter().map(|x| x.len()).sum::<usize>() as u16
         );
 
+        assert_eq!(message_buffer.end_offsets[0], 9_718 - 2);
+        assert_eq!(message_buffer.end_offsets[1], 9_718 - 1);
+
+
+        let message_buffer: &MessageBuffer =
+            bytemuck::from_bytes(&account_info_data.as_slice()[8..header_len]);
+
 
         let iter = message_buffer.end_offsets.iter().take_while(|x| **x != 0);
         let mut start = header_len;
@@ -298,7 +275,6 @@ mod test {
         assert_eq!(message_buffer.end_offsets[2], 0);
     }
 
-
     #[test]
     fn test_put_all_long_vec() {
         let data = vec![
@@ -315,17 +291,12 @@ mod test {
 
         let header_len = MessageBuffer::HEADER_LEN as usize;
 
-
         let (header_bytes, body_bytes) = account_info_data.split_at_mut(header_len);
         let message_buffer: &mut MessageBuffer = bytemuck::from_bytes_mut(&mut header_bytes[8..]);
 
         let (num_msgs, num_bytes) = message_buffer.put_all_in_buffer(body_bytes, &data_bytes);
 
 
-        let message_buffer: &MessageBuffer =
-            bytemuck::from_bytes(&account_info_data.as_slice()[8..header_len]);
-
-
         assert_eq!(num_msgs, 3);
         assert_eq!(
             num_bytes,
@@ -333,6 +304,9 @@ mod test {
         );
 
 
+        let message_buffer: &MessageBuffer =
+            bytemuck::from_bytes(&account_info_data.as_slice()[8..header_len]);
+
         let iter = message_buffer.end_offsets.iter().take_while(|x| **x != 0);
         let mut start = header_len;
         let mut data_iter = data_bytes.iter();
@@ -368,13 +342,9 @@ mod test {
         let message_buffer: &mut MessageBuffer = bytemuck::from_bytes_mut(&mut header_bytes[8..]);
 
         let (num_msgs, num_bytes) = message_buffer.put_all_in_buffer(body_bytes, &data_bytes);
+
         assert_eq!(num_msgs, 2);
         assert_eq!(num_bytes, 5);
-
-
-        let message_buffer: &MessageBuffer =
-            bytemuck::from_bytes(&account_info_data.as_slice()[8..header_len]);
-
         assert_eq!(message_buffer.end_offsets[0], 2);
         assert_eq!(message_buffer.end_offsets[1], 5);
 

+ 2 - 2
pythnet/message_buffer/programs/message_buffer/src/state/whitelist.rs

@@ -58,10 +58,10 @@ pub struct WhitelistVerifier<'info> {
 }
 
 impl<'info> WhitelistVerifier<'info> {
-    pub fn is_allowed(&self) -> Result<Pubkey> {
+    pub fn is_allowed(&self) -> Result<()> {
         let auth = self.cpi_caller_auth.key();
         let whitelist = &self.whitelist;
         whitelist.is_allowed_program_auth(&auth)?;
-        Ok(auth)
+        Ok(())
     }
 }

+ 184 - 8
pythnet/message_buffer/programs/mock-cpi-caller/tests/cases/test_resize_buffer.rs

@@ -90,6 +90,7 @@ async fn test_multiple_resize_buffer_ixs_in_same_txn() {
 }
 
 #[tokio::test]
+#[should_panic]
 async fn fail_resize_buffer_invalid_increase() {
     let mut context = MessageBufferTestContext::initialize_with_default_test_buffer(
         false,
@@ -111,7 +112,6 @@ async fn fail_resize_buffer_invalid_increase() {
     let resize_ix = resize_msg_buffer_ix(
         cpi_caller_auth,
         pyth_price_acct,
-        msg_buffer_bump,
         target_size,
         whitelist,
         admin.pubkey(),
@@ -125,16 +125,173 @@ async fn fail_resize_buffer_invalid_increase() {
     let err: ProgramError = res.unwrap_err().into();
     assert_eq!(
         err,
-        ProgramError::Custom(MessageBufferError::TargetSizeDeltaExceeded.into())
+        ProgramError::Custom(anchor_lang::error::ErrorCode::AccountReallocExceedsLimit.into())
     );
 
 
-    // shrink buffer size to less than minimum allowed
-    let target_size = 1;
+    let msg_buffer_account_data = context
+        .fetch_msg_buffer_account_data(&msg_buffer_pda)
+        .await
+        .unwrap();
+
+
+    assert_eq!(
+        msg_buffer_account_data.len(),
+        MessageBufferTestContext::DEFAULT_TARGET_SIZE as usize
+    );
+
+    let (bump, _version, _header_len, end_offsets) =
+        deserialize_msg_buffer_header(&msg_buffer_account_data);
+
+    assert_eq!(bump, msg_buffer_bump);
+    assert_eq!(end_offsets, [0u16; 255]);
+
+    // shrink buffer size to less than MessageBuffer::HEADER_LEN
+    let target_size = 15;
+    let resize_ix = resize_msg_buffer_ix(
+        cpi_caller_auth,
+        pyth_price_acct,
+        target_size,
+        whitelist,
+        admin.pubkey(),
+        msg_buffer_pda,
+    );
+
+    // a target_size less than the MessageBuffer::HEADER_LEN
+    // will result in a `ProgramFailedToComplete` (or AccountDiscriminatorNotFound
+    // if target_size < 8) since after the realloc,
+    // the AccountLoadder.load/load_mut() calls will fail
+    context
+        .process_ixs(&[resize_ix], vec![&admin])
+        .await
+        .unwrap();
+}
+
+#[tokio::test]
+async fn test_resize_initialized_buffer() {
+    let mut context = MessageBufferTestContext::initialize_with_default_test_buffer(
+        false,
+        MessageBufferTestContext::DEFAULT_TARGET_SIZE,
+    )
+    .await
+    .unwrap();
+
+    let payer = context.payer.pubkey();
+
+    let whitelist = context.whitelist();
+    let cpi_caller_auth = MessageBufferTestContext::get_mock_cpi_auth();
+    let (msg_buffer_pda, msg_buffer_bump) = MessageBufferTestContext::default_msg_buffer();
+
+    let add_price_params = MessageBufferTestContext::DEFAULT_ADD_PRICE_PARAMS;
+    context
+        .add_price(add_price_params, payer, whitelist, cpi_caller_auth)
+        .await
+        .unwrap();
+
+    let (id, price, price_expo, ema, ema_expo) = add_price_params;
+
+    let msg_buffer_account_data = context
+        .fetch_msg_buffer_account_data(&msg_buffer_pda)
+        .await
+        .unwrap();
+
+
+    let (bump, _version, header_len, end_offsets) =
+        deserialize_msg_buffer_header(&msg_buffer_account_data);
+
+    assert_eq!(bump, msg_buffer_bump);
+    // size_of(price::MessageHeader) + FullPriceMessage::SIZE
+    let msg_size_0 = 7 + 40;
+    assert_eq!(&end_offsets[0], &msg_size_0);
+
+    // size_of(price::MessageHeader) + CompactPriceMessage::SIZE
+    let msg_size_1 = 7 + 24;
+    assert_eq!(&end_offsets[1], &(msg_size_0 + msg_size_1));
+
+    assert_eq!(&end_offsets[2..], &[0u16; 253]);
+
+    let msgs = extract_msg_buffer_messages(header_len, end_offsets, &msg_buffer_account_data);
+    validate_price_msgs(id, price, price_expo, ema, ema_expo, &msgs).unwrap();
+
+
+    // increase buffer size should not edit the original data
+    let target_size = MessageBufferTestContext::DEFAULT_TARGET_SIZE + 10240;
+    let target_sizes = vec![target_size];
+    context
+        .resize_msg_buffer(
+            MessageBufferTestContext::DEFAULT_TEST_PRICE_ID,
+            target_sizes,
+        )
+        .await
+        .unwrap();
+
+
+    let msg_buffer_account_data = context
+        .fetch_msg_buffer_account_data(&msg_buffer_pda)
+        .await
+        .unwrap();
+
+    let (bump, _version, header_len, end_offsets) =
+        deserialize_msg_buffer_header(&msg_buffer_account_data);
+
+    assert_eq!(bump, msg_buffer_bump);
+    // size_of(price::MessageHeader) + FullPriceMessage::SIZE
+    let msg_size_0 = 7 + 40;
+    assert_eq!(&end_offsets[0], &msg_size_0);
+
+    // size_of(price::MessageHeader) + CompactPriceMessage::SIZE
+    let msg_size_1 = 7 + 24;
+    assert_eq!(&end_offsets[1], &(msg_size_0 + msg_size_1));
+
+    assert_eq!(&end_offsets[2..], &[0u16; 253]);
+
+    let msgs = extract_msg_buffer_messages(header_len, end_offsets, &msg_buffer_account_data);
+    validate_price_msgs(id, price, price_expo, ema, ema_expo, &msgs).unwrap();
+}
+
+#[tokio::test]
+async fn fail_resize_initialized_buffer() {
+    let mut context = MessageBufferTestContext::initialize_with_default_test_buffer(
+        false,
+        MessageBufferTestContext::DEFAULT_TARGET_SIZE,
+    )
+    .await
+    .unwrap();
+
+    let payer = context.payer.pubkey();
+    let admin = context.default_admin();
+    let pyth_price_acct = MessageBufferTestContext::default_pyth_price_account();
+    let whitelist = context.whitelist();
+    let cpi_caller_auth = MessageBufferTestContext::get_mock_cpi_auth();
+    let (msg_buffer_pda, _msg_buffer_bump) = MessageBufferTestContext::default_msg_buffer();
+
+    let add_price_params = MessageBufferTestContext::DEFAULT_ADD_PRICE_PARAMS;
+    context
+        .add_price(add_price_params, payer, whitelist, cpi_caller_auth)
+        .await
+        .unwrap();
+
+
+    let msg_buffer_account_data = context
+        .fetch_msg_buffer_account_data(&msg_buffer_pda)
+        .await
+        .unwrap();
+
+
+    let (_, _version, header_len, end_offsets) =
+        deserialize_msg_buffer_header(&msg_buffer_account_data);
+
+    let max_end_offset = end_offsets.iter().max().unwrap();
+    let min_size = header_len + max_end_offset;
+
+
+    // decrease buffer size to less than something that can fit the current messages
+    let target_size = (min_size as u32) - 1;
+
+
     let resize_ix = resize_msg_buffer_ix(
         cpi_caller_auth,
         pyth_price_acct,
-        msg_buffer_bump,
         target_size,
         whitelist,
         admin.pubkey(),
@@ -144,13 +301,32 @@ async fn fail_resize_buffer_invalid_increase() {
     let res = context.process_ixs(&[resize_ix], vec![&admin]).await;
 
     assert!(res.is_err());
+
     let err: ProgramError = res.unwrap_err().into();
     assert_eq!(
         err,
         ProgramError::Custom(MessageBufferError::MessageBufferTooSmall.into())
     );
-}
 
-#[tokio::test]
-async fn test_resize_initialized_buffer() {
+    let target_size = (min_size as u32) + 1;
+
+
+    let resize_ix = resize_msg_buffer_ix(
+        cpi_caller_auth,
+        pyth_price_acct,
+        target_size,
+        whitelist,
+        admin.pubkey(),
+        msg_buffer_pda,
+    );
+
+    let res = context.process_ixs(&[resize_ix], vec![&admin]).await;
+
+    assert!(res.is_ok());
+    let msg_buffer_account_data = context
+        .fetch_msg_buffer_account_data(&msg_buffer_pda)
+        .await
+        .unwrap();
+
+    assert_eq!(msg_buffer_account_data.len(), target_size as usize);
 }

+ 7 - 14
pythnet/message_buffer/programs/mock-cpi-caller/tests/program_test/mod.rs

@@ -192,7 +192,10 @@ impl MessageBufferTestContext {
                 let e = Custom(error_code);
                 Err(e.into())
             }
-            Err(_) => panic!("Unexpected error"),
+            Err(e) => {
+                println!("proces_ixs Error: {:?}", e);
+                panic!("Non Custom Ix Error in process_ixs{:?}", e);
+            }
             Ok(_) => Ok(()),
         }
     }
@@ -287,14 +290,13 @@ impl MessageBufferTestContext {
     pub async fn delete_buffer(&mut self, id: u64) -> anchor_lang::Result<()> {
         let pyth_price_account = Self::get_mock_pyth_price_account(id);
 
-        let (msg_buffer_pda, msg_buffer_bump) =
+        let (msg_buffer_pda, _) =
             find_msg_buffer_pda(Self::get_mock_cpi_auth(), pyth_price_account);
         let admin = self.admin.as_ref().unwrap().insecure_clone();
 
         let delete_ix = delete_msg_buffer_ix(
             Self::get_mock_cpi_auth(),
             pyth_price_account,
-            msg_buffer_bump,
             self.whitelist(),
             admin.pubkey(),
             msg_buffer_pda,
@@ -310,7 +312,7 @@ impl MessageBufferTestContext {
         target_sizes: Vec<u32>,
     ) -> anchor_lang::Result<()> {
         let pyth_price_account = Self::get_mock_pyth_price_account(id);
-        let (msg_buffer_pda, msg_buffer_bump) =
+        let (msg_buffer_pda, _) =
             find_msg_buffer_pda(Self::get_mock_cpi_auth(), pyth_price_account);
 
         let resize_ixs = &mut vec![];
@@ -322,7 +324,6 @@ impl MessageBufferTestContext {
             let resize_ix = resize_msg_buffer_ix(
                 Self::get_mock_cpi_auth(),
                 pyth_price_account,
-                msg_buffer_bump,
                 target_size,
                 self.whitelist(),
                 admin.pubkey(),
@@ -430,7 +431,6 @@ pub fn create_msg_buffer_ix(
 pub fn resize_msg_buffer_ix(
     cpi_caller_auth: Pubkey,
     pyth_price_acct: Pubkey,
-    msg_buffer_bump: u8,
     target_size: u32,
     whitelist: Pubkey,
     admin: Pubkey,
@@ -444,7 +444,6 @@ pub fn resize_msg_buffer_ix(
             resize_ix_disc,
             cpi_caller_auth,
             pyth_price_acct,
-            msg_buffer_bump,
             target_size,
         ),
         vec![
@@ -460,7 +459,6 @@ pub fn resize_msg_buffer_ix(
 pub fn delete_msg_buffer_ix(
     cpi_caller_auth: Pubkey,
     pyth_price_acct: Pubkey,
-    msg_buffer_bump: u8,
     whitelist: Pubkey,
     admin: Pubkey,
     msg_buffer_pda: Pubkey,
@@ -469,12 +467,7 @@ pub fn delete_msg_buffer_ix(
 
     Instruction::new_with_borsh(
         ::message_buffer::id(),
-        &(
-            delete_ix_disc,
-            cpi_caller_auth,
-            pyth_price_acct,
-            msg_buffer_bump,
-        ),
+        &(delete_ix_disc, cpi_caller_auth, pyth_price_acct),
         vec![
             AccountMeta::new_readonly(whitelist, false),
             AccountMeta::new(admin, true),

+ 13 - 28
pythnet/message_buffer/tests/message_buffer.ts

@@ -65,7 +65,7 @@ const [messageBufferPda2, messageBufferBump2] =
     messageBufferProgram.programId
   );
 
-const accumulatorPdaMeta2 = {
+const messageBufferPdaMeta2 = {
   pubkey: messageBufferPda2,
   isSigner: false,
   isWritable: true,
@@ -144,7 +144,7 @@ describe("message_buffer", () => {
   });
 
   it("Creates a buffer", async () => {
-    const accumulatorPdaMetas = [
+    const msgBufferPdaMetas = [
       {
         pubkey: messageBufferPda,
         isSigner: false,
@@ -160,7 +160,7 @@ describe("message_buffer", () => {
         systemProgram: anchor.web3.SystemProgram.programId,
       })
       .signers([whitelistAdmin])
-      .remainingAccounts(accumulatorPdaMetas)
+      .remainingAccounts(msgBufferPdaMetas)
       .rpc({ skipPreflight: true });
 
     const messageBufferAccountData = await getMessageBuffer(
@@ -206,7 +206,7 @@ describe("message_buffer", () => {
         systemProgram: anchor.web3.SystemProgram.programId,
       })
       .signers([whitelistAdmin])
-      .remainingAccounts([accumulatorPdaMeta2])
+      .remainingAccounts([messageBufferPdaMeta2])
       .rpc({ skipPreflight: true });
 
     const messageBufferAccountData = await getMessageBuffer(
@@ -560,19 +560,13 @@ describe("message_buffer", () => {
     );
     const targetSize = 10 * 1024;
     await messageBufferProgram.methods
-      .resizeBuffer(
-        mockCpiCallerAuth,
-        pythPriceAccountPk2,
-        messageBufferBump2,
-        targetSize
-      )
+      .resizeBuffer(mockCpiCallerAuth, pythPriceAccountPk2, targetSize)
       .accounts({
         whitelist: whitelistPubkey,
         admin: whitelistAdmin.publicKey,
         systemProgram: anchor.web3.SystemProgram.programId,
       })
       .signers([whitelistAdmin])
-      .remainingAccounts([accumulatorPdaMeta2])
       .rpc({ skipPreflight: true });
 
     const whitelistAuthorityBalanceAfter = await provider.connection.getBalance(
@@ -606,19 +600,14 @@ describe("message_buffer", () => {
   it("Resizes a buffer to a smaller size", async () => {
     const targetSize = 4 * 1024;
     await messageBufferProgram.methods
-      .resizeBuffer(
-        mockCpiCallerAuth,
-        pythPriceAccountPk2,
-        messageBufferBump2,
-        targetSize
-      )
+      .resizeBuffer(mockCpiCallerAuth, pythPriceAccountPk2, targetSize)
       .accounts({
         whitelist: whitelistPubkey,
         admin: whitelistAdmin.publicKey,
         systemProgram: anchor.web3.SystemProgram.programId,
+        messageBuffer: messageBufferPda2,
       })
       .signers([whitelistAdmin])
-      .remainingAccounts([accumulatorPdaMeta2])
       .rpc({ skipPreflight: true });
 
     const messageBufferAccountData = await getMessageBuffer(
@@ -635,19 +624,14 @@ describe("message_buffer", () => {
       let errorThrown = false;
       try {
         await messageBufferProgram.methods
-          .resizeBuffer(
-            mockCpiCallerAuth,
-            pythPriceAccountPk2,
-            messageBufferBump2,
-            testCase
-          )
+          .resizeBuffer(mockCpiCallerAuth, pythPriceAccountPk2, testCase)
           .accounts({
             whitelist: whitelistPubkey,
             admin: whitelistAdmin.publicKey,
             systemProgram: anchor.web3.SystemProgram.programId,
+            messageBuffer: messageBufferPda2,
           })
           .signers([whitelistAdmin])
-          .remainingAccounts([accumulatorPdaMeta2])
           .rpc({ skipPreflight: true });
       } catch (_err) {
         errorThrown = true;
@@ -658,13 +642,14 @@ describe("message_buffer", () => {
 
   it("Deletes a buffer", async () => {
     await messageBufferProgram.methods
-      .deleteBuffer(mockCpiCallerAuth, pythPriceAccountPk2, messageBufferBump2)
+      .deleteBuffer(mockCpiCallerAuth, pythPriceAccountPk2)
       .accounts({
         whitelist: whitelistPubkey,
         admin: whitelistAdmin.publicKey,
+        messageBuffer: messageBufferPda2,
       })
       .signers([whitelistAdmin])
-      .remainingAccounts([accumulatorPdaMeta2])
+      .remainingAccounts([messageBufferPdaMeta2])
       .rpc({ skipPreflight: true });
 
     const messageBufferAccountData = await getMessageBuffer(
@@ -697,7 +682,7 @@ describe("message_buffer", () => {
         systemProgram: anchor.web3.SystemProgram.programId,
       })
       .signers([whitelistAdmin])
-      .remainingAccounts([accumulatorPdaMeta2])
+      .remainingAccounts([messageBufferPdaMeta2])
       .rpc({ skipPreflight: true });
 
     const messageBufferAccountData = await getMessageBuffer(