Skip to content

Commit 3f7447c

Browse files
fix(quasar/compression): unwrap RemainingAccount to AccountView
Newer quasar-lang (post-PR-solana-developers#195 era) changed RemainingAccounts::iter() to yield Result<RemainingAccount, _> instead of Result<AccountView, _>, so the existing 'proof_views[i] = result?' assignments stopped compiling. RemainingAccount is a safe wrapper around AccountView. We only need the inner view to forward to the bubblegum / spl-account-compression CPI as read-only proof nodes (no data borrows, no aliasing risk), so reach for 'as_account_view_unchecked' inside an unsafe block. Affects: - compression/cnft-burn/quasar (burn CPI proof nodes) - compression/cnft-vault/quasar (withdraw / withdraw_two transfer CPI) - compression/cutils/quasar (verify_leaf CPI)
1 parent 0919a9d commit 3f7447c

4 files changed

Lines changed: 37 additions & 8 deletions

File tree

compression/cnft-burn/quasar/src/instructions/burn_cnft.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,12 @@ pub fn handle_burn_cnft(accounts: &mut BurnCnft, data: &[u8], remaining: Remaini
4343
ix_data[0..8].copy_from_slice(&BURN_DISCRIMINATOR);
4444
ix_data[8..116].copy_from_slice(&data[0..108]);
4545

46-
// Collect remaining accounts (proof nodes) into a stack buffer
46+
// Collect remaining accounts (proof nodes) into a stack buffer.
47+
//
48+
// `remaining.iter()` yields `Result<RemainingAccount, _>` in newer
49+
// quasar-lang. Reach the inner `AccountView` via the unchecked accessor
50+
// — this CPI only reads proof addresses and views, never touching the
51+
// accounts' data, so the aliasing/borrow invariants are upheld.
4752
let placeholder = accounts.system_program.to_account_view().clone();
4853
let mut proof_views: [AccountView; MAX_PROOF_NODES] =
4954
core::array::from_fn(|_| placeholder.clone());
@@ -52,7 +57,10 @@ pub fn handle_burn_cnft(accounts: &mut BurnCnft, data: &[u8], remaining: Remaini
5257
if proof_count >= MAX_PROOF_NODES {
5358
break;
5459
}
55-
proof_views[proof_count] = result?;
60+
let account = result?;
61+
// SAFETY: We only read the AccountView's address and pass an immutable
62+
// view to the bubblegum CPI as a proof node; no aliased data access.
63+
proof_views[proof_count] = unsafe { account.as_account_view_unchecked() }.clone();
5664
proof_count += 1;
5765
}
5866

compression/cnft-vault/quasar/src/instructions/withdraw.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,12 @@ pub fn handle_withdraw_cnft(accounts: &mut Withdraw, data: &[u8], remaining: Rem
5050

5151
let ix_data = build_transfer_data(&data[0..TRANSFER_ARGS_LEN]);
5252

53-
// Collect proof nodes
53+
// Collect proof nodes.
54+
//
55+
// `remaining.iter()` yields `Result<RemainingAccount, _>` in newer
56+
// quasar-lang. Reach the inner `AccountView` via the unchecked accessor
57+
// — we only read addresses/views to forward to the bubblegum CPI as
58+
// proof nodes; no aliased data access.
5459
let placeholder = accounts.system_program.to_account_view().clone();
5560
let mut proof_views: [AccountView; MAX_PROOF_NODES] =
5661
core::array::from_fn(|_| placeholder.clone());
@@ -59,7 +64,9 @@ pub fn handle_withdraw_cnft(accounts: &mut Withdraw, data: &[u8], remaining: Rem
5964
if proof_count >= MAX_PROOF_NODES {
6065
break;
6166
}
62-
proof_views[proof_count] = result?;
67+
let account = result?;
68+
// SAFETY: Only reads address and forwards an immutable view to CPI.
69+
proof_views[proof_count] = unsafe { account.as_account_view_unchecked() }.clone();
6370
proof_count += 1;
6471
}
6572

compression/cnft-vault/quasar/src/instructions/withdraw_two.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,12 @@ pub fn handle_withdraw_two_cnfts(accounts: &mut WithdrawTwo, data: &[u8], remain
6565
];
6666
let signer = Signer::from(&seeds as &[Seed]);
6767

68-
// Collect all remaining accounts (proof1 ++ proof2)
68+
// Collect all remaining accounts (proof1 ++ proof2).
69+
//
70+
// `remaining.iter()` yields `Result<RemainingAccount, _>` in newer
71+
// quasar-lang. Reach the inner `AccountView` via the unchecked accessor
72+
// — we only read addresses/views to forward to the bubblegum CPIs as
73+
// proof nodes; no aliased data access.
6974
let placeholder = accounts.system_program.to_account_view().clone();
7075
let mut all_proofs: [AccountView; MAX_PROOF_NODES * 2] =
7176
core::array::from_fn(|_| placeholder.clone());
@@ -74,7 +79,9 @@ pub fn handle_withdraw_two_cnfts(accounts: &mut WithdrawTwo, data: &[u8], remain
7479
if total_proofs >= MAX_PROOF_NODES * 2 {
7580
break;
7681
}
77-
all_proofs[total_proofs] = result?;
82+
let account = result?;
83+
// SAFETY: Only reads address and forwards an immutable view to CPI.
84+
all_proofs[total_proofs] = unsafe { account.as_account_view_unchecked() }.clone();
7885
total_proofs += 1;
7986
}
8087

compression/cutils/quasar/src/instructions/verify.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,12 @@ pub fn handle_verify(accounts: &mut Verify, data: &[u8], remaining: RemainingAcc
5555
ix_data[40..72].copy_from_slice(&leaf_hash);
5656
ix_data[72..76].copy_from_slice(&index.to_le_bytes());
5757

58-
// Collect proof nodes
58+
// Collect proof nodes.
59+
//
60+
// `remaining.iter()` yields `Result<RemainingAccount, _>` in newer
61+
// quasar-lang. Reach the inner `AccountView` via the unchecked accessor
62+
// — we only read addresses/views to forward to the compression CPI as
63+
// proof nodes; no aliased data access.
5964
let placeholder = accounts.compression_program.to_account_view().clone();
6065
let mut proof_views: [AccountView; MAX_PROOF_NODES] =
6166
core::array::from_fn(|_| placeholder.clone());
@@ -64,7 +69,9 @@ pub fn handle_verify(accounts: &mut Verify, data: &[u8], remaining: RemainingAcc
6469
if proof_count >= MAX_PROOF_NODES {
6570
break;
6671
}
67-
proof_views[proof_count] = result?;
72+
let account = result?;
73+
// SAFETY: Only reads address and forwards an immutable view to CPI.
74+
proof_views[proof_count] = unsafe { account.as_account_view_unchecked() }.clone();
6875
proof_count += 1;
6976
}
7077

0 commit comments

Comments
 (0)