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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 0 additions & 40 deletions .cargo/config.toml

This file was deleted.

87 changes: 71 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion anchor-programs/system/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ test-sbf = []
aligned-sized = { workspace = true }
anchor-lang = { workspace = true }
account-compression = { workspace = true, features = ["cpi"] }
light-compressed-account = { workspace = true }
light-compressed-account = { workspace = true, features = ["new-unique"] }
light-zero-copy = { workspace = true }
zerocopy = { workspace = true }

Expand Down
15 changes: 12 additions & 3 deletions anchor-programs/system/src/cpi_context_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,31 @@ pub struct CpiContextAccount {
pub context: Vec<InstructionDataInvokeCpi>,
}

#[aligned_sized(anchor)]
#[derive(Debug, PartialEq, Default)]
#[account]
#[repr(C)]
pub struct CpiContextAccount2 {
pub fee_payer: Pubkey,
pub associated_merkle_tree: Pubkey,
}
Comment on lines +28 to +35
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Layout/deserialization mismatch between v1 and v2 context accounts

CpiContextAccount2 removes the context Vec, but deserialize_cpi_context_account still reads a length and iterates context items. On v2 data this will read past the struct and return corrupted data.

Parse by discriminator and handle both layouts:

-use anchor_lang::prelude::*;
+use anchor_lang::{prelude::*, Discriminator};
@@
-pub fn deserialize_cpi_context_account<'info, 'a>(
-    account_info: &AccountInfo<'info>,
-) -> std::result::Result<ZCpiContextAccount2<'a>, ZeroCopyError> {
-    let mut account_data = account_info.try_borrow_mut_data().unwrap();
-    let data = unsafe { slice::from_raw_parts_mut(account_data.as_mut_ptr(), account_data.len()) };
-    let (fee_payer, data) =
-        Ref::<&'a mut [u8], light_compressed_account::pubkey::Pubkey>::from_prefix(&mut data[8..])?;
-    let (associated_merkle_tree, data) =
-        Ref::<&'a mut [u8], light_compressed_account::pubkey::Pubkey>::from_prefix(data)?;
-    let (len, data) = Ref::<&'a mut [u8], U32>::from_prefix(data)?;
-    let mut data = &*data;
-    let mut context = Vec::new();
-    for _ in 0..(u64::from(*len)) as usize {
-        let (context_item, new_data) = ZInstructionDataInvokeCpi::zero_copy_at(data)?;
-        context.push(context_item);
-        data = new_data;
-    }
-    Ok(ZCpiContextAccount2 { fee_payer, associated_merkle_tree, context })
-}
+pub fn deserialize_cpi_context_account<'info, 'a>(
+    account_info: &AccountInfo<'info>,
+) -> std::result::Result<ZCpiContextAccount2<'a>, ZeroCopyError> {
+    let mut account_data = account_info.try_borrow_mut_data().map_err(|_| ZeroCopyError::BorrowMut)?;
+    let data = unsafe { slice::from_raw_parts_mut(account_data.as_mut_ptr(), account_data.len()) };
+    let discr = &data[..8];
+    // Old layout with context Vec
+    if discr == CpiContextAccount::discriminator() {
+        let (fee_payer, data) =
+            Ref::<&'a mut [u8], light_compressed_account::pubkey::Pubkey>::from_prefix(&mut data[8..])?;
+        let (associated_merkle_tree, data) =
+            Ref::<&'a mut [u8], light_compressed_account::pubkey::Pubkey>::from_prefix(data)?;
+        let (len, data) = Ref::<&'a mut [u8], U32>::from_prefix(data)?;
+        let mut data = &*data;
+        let mut context = Vec::new();
+        for _ in 0..(u64::from(*len)) as usize {
+            let (context_item, new_data) = ZInstructionDataInvokeCpi::zero_copy_at(data)?;
+            context.push(context_item);
+            data = new_data;
+        }
+        return Ok(ZCpiContextAccount2 { fee_payer, associated_merkle_tree, context });
+    }
+    // New v2 layout without context Vec
+    if discr == CpiContextAccount2::discriminator() {
+        let (fee_payer, data) =
+            Ref::<&'a mut [u8], light_compressed_account::pubkey::Pubkey>::from_prefix(&mut data[8..])?;
+        let (associated_merkle_tree, _rest) =
+            Ref::<&'a mut [u8], light_compressed_account::pubkey::Pubkey>::from_prefix(data)?;
+        return Ok(ZCpiContextAccount2 { fee_payer, associated_merkle_tree, context: Vec::new() });
+    }
+    Err(ZeroCopyError::InvalidDiscriminator)
+}

Also consider returning a versioned enum if callers need to distinguish v1 vs v2.

Also applies to: 44-72, 50-53


impl CpiContextAccount {
pub fn init(&mut self, associated_merkle_tree: Pubkey) {
self.associated_merkle_tree = associated_merkle_tree;
self.context = Vec::new();
}
}

pub struct ZCpiContextAccount<'a> {
pub struct ZCpiContextAccount2<'a> {
pub fee_payer: Ref<&'a mut [u8], light_compressed_account::pubkey::Pubkey>,
pub associated_merkle_tree: Ref<&'a mut [u8], light_compressed_account::pubkey::Pubkey>,
pub context: Vec<ZInstructionDataInvokeCpi<'a>>,
}

pub fn deserialize_cpi_context_account<'info, 'a>(
account_info: &AccountInfo<'info>,
) -> std::result::Result<ZCpiContextAccount<'a>, ZeroCopyError> {
) -> std::result::Result<ZCpiContextAccount2<'a>, ZeroCopyError> {
let mut account_data = account_info.try_borrow_mut_data().unwrap();
let data = unsafe { slice::from_raw_parts_mut(account_data.as_mut_ptr(), account_data.len()) };
let (fee_payer, data) =
Expand All @@ -55,7 +64,7 @@ pub fn deserialize_cpi_context_account<'info, 'a>(
context.push(context_item);
data = new_data;
}
Ok(ZCpiContextAccount {
Ok(ZCpiContextAccount2 {
fee_payer,
associated_merkle_tree,
context,
Expand Down
4 changes: 4 additions & 0 deletions anchor-programs/system/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ pub mod light_system_program {
unimplemented!("anchor wrapper not implemented")
}

pub fn re_init_cpi_context_account(ctx: Context<InitializeCpiContextAccount>) -> Result<()> {
unimplemented!("anchor wrapper not implemented")
}
Comment on lines +28 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Gate unimplemented Anchor wrappers to avoid accidental on-chain panics.

Since these handlers are unimplemented!(), ensure they can’t be compiled into a deployed SBF build.

Apply per-function gating now, and consider gating the entire #[program] block similarly:

+#[cfg(feature = "idl-build")]
 pub fn re_init_cpi_context_account(ctx: Context<InitializeCpiContextAccount>) -> Result<()> {
     unimplemented!("anchor wrapper not implemented")
 }

Additionally (outside this hunk), add at crate root:

#[cfg(all(target_os = "solana"), not(feature = "idl-build"))]
compile_error!("Anchor wrappers must not be built for on-chain use; enable feature `idl-build` only for IDL generation.");

⚠️ Potential issue

Incorrect context type for re-init instruction.

This should use the re-init accounts context, not InitializeCpiContextAccount. Otherwise the IDL and account constraints for re-init will be wrong.

Apply:

-pub fn re_init_cpi_context_account(ctx: Context<InitializeCpiContextAccount>) -> Result<()> {
+pub fn re_init_cpi_context_account(ctx: Context<ReInitCpiContextAccount>) -> Result<()> {
     unimplemented!("anchor wrapper not implemented")
 }

Please replace ReInitCpiContextAccount with the exact type name defined in instructions::* if it differs.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub fn re_init_cpi_context_account(ctx: Context<InitializeCpiContextAccount>) -> Result<()> {
unimplemented!("anchor wrapper not implemented")
}
pub fn re_init_cpi_context_account(ctx: Context<ReInitCpiContextAccount>) -> Result<()> {
unimplemented!("anchor wrapper not implemented")
}
🤖 Prompt for AI Agents
In anchor-programs/system/src/lib.rs around lines 28 to 30, the
re_init_cpi_context_account function is using the wrong context type
(Context<InitializeCpiContextAccount>); replace it with the re-init accounts
context type defined in instructions::* (e.g., Context<ReInitCpiContextAccount>
or the exact name in instructions), update any imports to bring that type into
scope, and adjust any references so the function signature and IDL reflect the
correct re-init account constraints.


pub fn invoke(ctx: Context<InvokeInstruction>, inputs: Vec<u8>) -> Result<()> {
unimplemented!("anchor wrapper not implemented")
}
Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading
Loading