Skip to content

Commit 27749d3

Browse files
force apps to pass the whole signer_seeds directly
1 parent 2a4c73c commit 27749d3

File tree

5 files changed

+76
-73
lines changed

5 files changed

+76
-73
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

program-tests/anchor-compressible-user/src/lib.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use light_sdk::{
66
light_hasher::{DataHasher, Hasher},
77
};
88
use light_sdk::{derive_light_cpi_signer, LightDiscriminator, LightHasher};
9-
use light_sdk_types::CpiAccountsConfig;
109
use light_sdk_types::CpiSigner;
1110

1211
declare_id!("CompUser11111111111111111111111111111111111");
@@ -81,14 +80,15 @@ pub mod anchor_compressible_user {
8180
ctx: Context<'_, '_, '_, 'info, DecompressMultiplePdas<'info>>,
8281
proof: ValidityProof,
8382
compressed_accounts: Vec<CompressedAccountData>,
83+
bumps: Vec<u8>,
8484
system_accounts_offset: u8,
8585
) -> Result<()> {
8686
// Get PDA accounts from remaining accounts
8787
let pda_accounts_end = system_accounts_offset as usize;
8888
let pda_accounts = &ctx.remaining_accounts[..pda_accounts_end];
8989

90-
// Validate we have matching number of PDAs and compressed accounts
91-
if pda_accounts.len() != compressed_accounts.len() {
90+
// Validate we have matching number of PDAs, compressed accounts, and bumps
91+
if pda_accounts.len() != compressed_accounts.len() || pda_accounts.len() != bumps.len() {
9292
return err!(ErrorCode::InvalidAccountCount);
9393
}
9494

@@ -101,8 +101,13 @@ pub mod anchor_compressible_user {
101101
// Convert to unified enum accounts
102102
let mut light_accounts = Vec::new();
103103
let mut pda_account_refs = Vec::new();
104+
let mut signer_seeds_storage = Vec::new();
104105

105-
for (i, compressed_data) in compressed_accounts.into_iter().enumerate() {
106+
for (i, (compressed_data, bump)) in compressed_accounts
107+
.into_iter()
108+
.zip(bumps.iter())
109+
.enumerate()
110+
{
106111
// Convert to unified enum type
107112
let unified_account = match compressed_data.data {
108113
CompressedAccountVariant::UserRecord(data) => {
@@ -116,23 +121,52 @@ pub mod anchor_compressible_user {
116121
let light_account = LightAccount::<'_, CompressedAccountVariant>::new_mut(
117122
&crate::ID,
118123
&compressed_data.meta,
119-
unified_account,
124+
unified_account.clone(),
120125
)
121126
.map_err(|e| anchor_lang::prelude::ProgramError::from(e))?;
122127

128+
// Build signer seeds based on account type
129+
let seeds = match &unified_account {
130+
CompressedAccountVariant::UserRecord(data) => {
131+
vec![
132+
b"user_record".to_vec(),
133+
data.owner.to_bytes().to_vec(),
134+
vec![*bump],
135+
]
136+
}
137+
CompressedAccountVariant::GameSession(data) => {
138+
vec![
139+
b"game_session".to_vec(),
140+
data.session_id.to_le_bytes().to_vec(),
141+
vec![*bump],
142+
]
143+
}
144+
};
145+
146+
signer_seeds_storage.push(seeds);
123147
light_accounts.push(light_account);
124148
pda_account_refs.push(&pda_accounts[i]);
125149
}
126150

151+
// Convert to the format needed by the SDK
152+
let signer_seeds_refs: Vec<Vec<&[u8]>> = signer_seeds_storage
153+
.iter()
154+
.map(|seeds| seeds.iter().map(|s| s.as_slice()).collect())
155+
.collect();
156+
let signer_seeds_slices: Vec<&[&[u8]]> = signer_seeds_refs
157+
.iter()
158+
.map(|seeds| seeds.as_slice())
159+
.collect();
160+
127161
// Single CPI call with unified enum type
128162
decompress_multiple_idempotent::<CompressedAccountVariant>(
129163
&pda_account_refs,
130164
light_accounts,
165+
&signer_seeds_slices,
131166
proof,
132167
cpi_accounts,
133168
&crate::ID,
134169
&ctx.accounts.rent_payer,
135-
&ctx.accounts.system_program.to_account_info(),
136170
)
137171
.map_err(|e| anchor_lang::prelude::ProgramError::from(e))?;
138172

program-tests/sdk-test/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ borsh = { workspace = true }
2828
light-compressed-account = { workspace = true, features = ["solana"] }
2929
solana-clock = { workspace = true }
3030
solana-sysvar = { workspace = true }
31+
arrayvec = { workspace = true }
3132

3233
[dev-dependencies]
3334
light-program-test = { workspace = true, features = ["devenv"] }

program-tests/sdk-test/src/decompress_dynamic_pda.rs

Lines changed: 24 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1+
use arrayvec::ArrayVec;
12
use borsh::{BorshDeserialize, BorshSerialize};
23
use light_sdk::{
34
account::LightAccount,
45
compressible::{decompress_idempotent, CompressionTiming},
5-
cpi::{CpiAccounts, CpiAccountsConfig},
6+
cpi::CpiAccounts,
67
error::LightSdkError,
78
instruction::{account_meta::CompressedAccountMeta, ValidityProof},
89
LightDiscriminator, LightHasher,
@@ -24,14 +25,12 @@ pub fn decompress_dynamic_pda(
2425
let fee_payer = &accounts[0];
2526
let pda_account = &accounts[1];
2627
let rent_payer = &accounts[2];
27-
let system_program = &accounts[3];
2828

2929
// Set up CPI accounts
30-
let config = CpiAccountsConfig::new(crate::LIGHT_CPI_SIGNER);
31-
let cpi_accounts = CpiAccounts::new_with_config(
30+
let cpi_accounts = CpiAccounts::new(
3231
fee_payer,
3332
&accounts[instruction_data.system_accounts_offset as usize..],
34-
config,
33+
crate::LIGHT_CPI_SIGNER,
3534
);
3635

3736
let compressed_account = LightAccount::<'_, MyPdaAccount>::new_mut(
@@ -56,16 +55,15 @@ pub fn decompress_dynamic_pda(
5655
}
5756

5857
// Call decompress_idempotent with seeds - this should work whether PDA exists or not
58+
let signer_seeds: &[&[u8]] = &[b"test_pda", &account_data, &[bump]];
5959
decompress_idempotent::<MyPdaAccount>(
6060
pda_account,
6161
compressed_account,
62-
seeds,
63-
bump,
62+
signer_seeds,
6463
instruction_data.proof,
6564
cpi_accounts,
6665
&crate::ID,
6766
rent_payer,
68-
system_program,
6967
)?;
7068

7169
Ok(())
@@ -92,10 +90,9 @@ pub fn decompress_multiple_dynamic_pdas(
9290
// Get fixed accounts
9391
let fee_payer = &accounts[0];
9492
let rent_payer = &accounts[1];
95-
let system_program = &accounts[2];
9693

9794
// Get PDA accounts (after fixed accounts, before system accounts)
98-
let pda_accounts_start = 3;
95+
let pda_accounts_start = 2;
9996
let pda_accounts_end = instruction_data.system_accounts_offset as usize;
10097
let pda_accounts = &accounts[pda_accounts_start..pda_accounts_end];
10198

@@ -105,11 +102,10 @@ pub fn decompress_multiple_dynamic_pdas(
105102
crate::LIGHT_CPI_SIGNER,
106103
);
107104

108-
// Build inputs for batch decompression
105+
// Can be passed in; the custom program does not have to check the seeds.
109106
let mut compressed_accounts = Vec::new();
110107
let mut pda_account_refs = Vec::new();
111-
let mut all_seeds = Vec::new();
112-
let mut bumps = Vec::new();
108+
let mut all_signer_seeds = Vec::new();
113109

114110
for (i, compressed_account_data) in instruction_data.compressed_accounts.into_iter().enumerate()
115111
{
@@ -119,19 +115,13 @@ pub fn decompress_multiple_dynamic_pdas(
119115
compressed_account_data.data.clone(),
120116
)?;
121117

122-
// Store seeds in a vector to ensure they live long enough
123-
all_seeds.push(vec![
124-
b"test_pda".to_vec(),
125-
compressed_account_data.data.data.to_vec(),
126-
]);
127-
128-
// Create references to the seeds
129-
let seeds: Vec<&[u8]> = all_seeds
130-
.last()
131-
.unwrap()
132-
.iter()
133-
.map(|s| s.as_slice())
134-
.collect();
118+
// Create signer seeds with ArrayVec
119+
let mut signer_seeds = ArrayVec::<&[u8], 3>::new();
120+
signer_seeds.push(b"test_pda");
121+
signer_seeds.push(&compressed_account_data.data.data);
122+
123+
// Derive bump for verification
124+
let seeds: Vec<&[u8]> = vec![b"test_pda", &compressed_account_data.data.data];
135125
let (derived_pda, bump) =
136126
solana_program::pubkey::Pubkey::find_program_address(&seeds, &crate::ID);
137127

@@ -140,29 +130,29 @@ pub fn decompress_multiple_dynamic_pdas(
140130
return Err(LightSdkError::ConstraintViolation);
141131
}
142132

133+
// Add bump to signer seeds
134+
signer_seeds.push(&[bump]);
135+
143136
compressed_accounts.push(compressed_account);
144137
pda_account_refs.push(&pda_accounts[i]);
145-
bumps.push(bump);
138+
all_signer_seeds.push(signer_seeds);
146139
}
147140

148-
// Create seeds references for the function call
149-
let seeds_refs: Vec<Vec<&[u8]>> = all_seeds
141+
// Convert ArrayVecs to the format needed by the SDK
142+
let signer_seeds_refs: Vec<&[&[u8]]> = all_signer_seeds
150143
.iter()
151-
.map(|seeds| seeds.iter().map(|s| s.as_slice()).collect())
144+
.map(|seeds| seeds.as_slice())
152145
.collect();
153-
let seeds_list: Vec<&[&[u8]]> = seeds_refs.iter().map(|seeds| seeds.as_slice()).collect();
154146

155147
// Decompress all accounts in one CPI call
156148
decompress_multiple_idempotent::<MyPdaAccount>(
157149
&pda_account_refs,
158150
compressed_accounts,
159-
&seeds_list,
160-
&bumps,
151+
&signer_seeds_refs,
161152
instruction_data.proof,
162153
cpi_accounts,
163154
&crate::ID,
164155
rent_payer,
165-
system_program,
166156
)?;
167157

168158
Ok(())

sdk-libs/sdk/src/compressible/decompress_idempotent.rs

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use crate::{
77
};
88
#[cfg(feature = "anchor")]
99
use anchor_lang::{AnchorDeserialize as BorshDeserialize, AnchorSerialize as BorshSerialize};
10-
use arrayvec::ArrayVec;
1110
#[cfg(not(feature = "anchor"))]
1211
use borsh::{BorshDeserialize, BorshSerialize};
1312
use light_compressed_account::address::derive_address;
@@ -33,27 +32,23 @@ pub const COMPRESSION_DELAY: u64 = 100;
3332
/// # Arguments
3433
/// * `pda_account` - The PDA account to decompress into
3534
/// * `compressed_account` - The compressed account to decompress
36-
/// * `seeds` - The seeds used to derive the PDA
37-
/// * `bump` - The bump seed for the PDA
35+
/// * `signer_seeds` - The signer seeds including bump (standard Solana format)
3836
/// * `proof` - Validity proof
3937
/// * `cpi_accounts` - Accounts needed for CPI
4038
/// * `owner_program` - The program that will own the PDA
4139
/// * `rent_payer` - The account to pay for PDA rent
42-
/// * `system_program` - The system program
4340
///
4441
/// # Returns
4542
/// * `Ok(())` if the compressed account was decompressed successfully or PDA already exists
4643
/// * `Err(LightSdkError)` if there was an error
4744
pub fn decompress_idempotent<'info, A>(
4845
pda_account: &AccountInfo<'info>,
4946
compressed_account: LightAccount<'_, A>,
50-
seeds: &[&[u8]],
51-
bump: u8,
47+
signer_seeds: &[&[u8]],
5248
proof: ValidityProof,
5349
cpi_accounts: CpiAccounts<'_, 'info>,
5450
owner_program: &Pubkey,
5551
rent_payer: &AccountInfo<'info>,
56-
system_program: &AccountInfo<'info>,
5752
) -> Result<(), LightSdkError>
5853
where
5954
A: DataHasher
@@ -67,13 +62,11 @@ where
6762
decompress_multiple_idempotent(
6863
&[pda_account],
6964
vec![compressed_account],
70-
&[seeds],
71-
&[bump],
65+
&[signer_seeds],
7266
proof,
7367
cpi_accounts,
7468
owner_program,
7569
rent_payer,
76-
system_program,
7770
)
7871
}
7972

@@ -85,27 +78,23 @@ where
8578
/// # Arguments
8679
/// * `pda_accounts` - The PDA accounts to decompress into
8780
/// * `compressed_accounts` - The compressed accounts to decompress
88-
/// * `seeds_list` - List of seeds for each PDA (one per account)
89-
/// * `bumps` - List of bump seeds for each PDA (one per account)
81+
/// * `signer_seeds` - Signer seeds for each PDA including bump (standard Solana format)
9082
/// * `proof` - Single validity proof for all accounts
9183
/// * `cpi_accounts` - Accounts needed for CPI
9284
/// * `owner_program` - The program that will own the PDAs
9385
/// * `rent_payer` - The account to pay for PDA rent
94-
/// * `system_program` - The system program
9586
///
9687
/// # Returns
9788
/// * `Ok(())` if all compressed accounts were decompressed successfully or PDAs already exist
9889
/// * `Err(LightSdkError)` if there was an error
9990
pub fn decompress_multiple_idempotent<'info, A>(
10091
pda_accounts: &[&AccountInfo<'info>],
10192
compressed_accounts: Vec<LightAccount<'_, A>>,
102-
seeds_list: &[&[&[u8]]],
103-
bumps: &[u8],
93+
signer_seeds: &[&[&[u8]]],
10494
proof: ValidityProof,
10595
cpi_accounts: CpiAccounts<'_, 'info>,
10696
owner_program: &Pubkey,
10797
rent_payer: &AccountInfo<'info>,
108-
system_program: &AccountInfo<'info>,
10998
) -> Result<(), LightSdkError>
11099
where
111100
A: DataHasher
@@ -117,10 +106,7 @@ where
117106
+ CompressionTiming,
118107
{
119108
// Validate input lengths
120-
if pda_accounts.len() != compressed_accounts.len()
121-
|| pda_accounts.len() != seeds_list.len()
122-
|| pda_accounts.len() != bumps.len()
123-
{
109+
if pda_accounts.len() != compressed_accounts.len() || pda_accounts.len() != signer_seeds.len() {
124110
return Err(LightSdkError::ConstraintViolation);
125111
}
126112

@@ -131,11 +117,10 @@ where
131117

132118
let mut compressed_accounts_for_cpi = Vec::new();
133119

134-
for (((pda_account, mut compressed_account), seeds), &bump) in pda_accounts
120+
for ((pda_account, mut compressed_account), seeds) in pda_accounts
135121
.iter()
136122
.zip(compressed_accounts.into_iter())
137-
.zip(seeds_list.iter())
138-
.zip(bumps.iter())
123+
.zip(signer_seeds.iter())
139124
{
140125
// TODO: consider a COMPRESSED_DISCIMINATOR.
141126
// compress -> set compressed
@@ -184,22 +169,14 @@ where
184169
owner_program,
185170
);
186171

187-
// cpi for each pda
188-
let bump_seed = [bump];
189-
let mut signer_seeds = ArrayVec::<&[u8], 16>::new();
190-
for seed in seeds.iter() {
191-
signer_seeds.push(*seed);
192-
}
193-
signer_seeds.push(&bump_seed);
194-
195172
invoke_signed(
196173
&create_account_ix,
197174
&[
198175
rent_payer.clone(),
199176
(*pda_account).clone(),
200-
system_program.clone(),
177+
cpi_accounts.system_program()?.clone(),
201178
],
202-
&[&signer_seeds],
179+
&[seeds],
203180
)?;
204181

205182
// Initialize PDA with decompressed data and update slot

0 commit comments

Comments
 (0)