Skip to content

Commit f2bf713

Browse files
use hascompressioninfo and compressioninfo
1 parent 5cc5ff4 commit f2bf713

File tree

9 files changed

+103
-105
lines changed

9 files changed

+103
-105
lines changed

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

Lines changed: 32 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use anchor_lang::prelude::*;
22
use light_sdk::{
3-
compressible::{CompressibleConfig, CompressionTiming},
3+
compressible::{CompressibleConfig, CompressionInfo, HasCompressionInfo},
44
cpi::CpiAccounts,
55
instruction::{account_meta::CompressedAccountMeta, PackedAddressTreeInfo, ValidityProof},
66
light_hasher::{DataHasher, Hasher},
@@ -42,8 +42,9 @@ pub mod anchor_compressible_user {
4242
user_record.owner = ctx.accounts.user.key();
4343
user_record.name = name;
4444
user_record.score = 0;
45-
user_record.last_written_slot = Clock::get()?.slot;
46-
user_record.compression_delay = config.compression_delay as u64;
45+
// Initialize compression info with current slot
46+
user_record.compression_info = CompressionInfo::new()
47+
.map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?;
4748

4849
// Verify rent recipient matches config
4950
if ctx.accounts.rent_recipient.key() != config.rent_recipient {
@@ -88,7 +89,9 @@ pub mod anchor_compressible_user {
8889
user_record.owner = ctx.accounts.user.key();
8990
user_record.name = name;
9091
user_record.score = 0;
91-
user_record.compression_delay = COMPRESSION_DELAY;
92+
// Initialize compression info with current slot
93+
user_record.compression_info = CompressionInfo::new()
94+
.map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?;
9295

9396
let cpi_accounts = CpiAccounts::new(
9497
&ctx.accounts.user,
@@ -243,7 +246,7 @@ pub mod anchor_compressible_user {
243246
cpi_accounts,
244247
&crate::ID,
245248
&ctx.accounts.rent_recipient,
246-
COMPRESSION_DELAY, // Use the hardcoded value for legacy function
249+
&COMPRESSION_DELAY as u32, // Use the hardcoded value for legacy function
247250
)
248251
.map_err(|e| anchor_lang::prelude::ProgramError::from(e))?;
249252
Ok(())
@@ -278,7 +281,7 @@ pub mod anchor_compressible_user {
278281
cpi_accounts,
279282
&crate::ID,
280283
&ctx.accounts.rent_recipient,
281-
config.compression_delay as u64,
284+
&config.compression_delay,
282285
)
283286
.map_err(|e| anchor_lang::prelude::ProgramError::from(e))?;
284287
Ok(())
@@ -292,7 +295,7 @@ pub struct CreateRecordWithConfig<'info> {
292295
#[account(
293296
init,
294297
payer = user,
295-
space = 8 + 32 + 4 + 32 + 8 + 8 + 8, // discriminator + owner + string len + name + score + last_written_slot + compression_delay
298+
space = 8 + 32 + 4 + 32 + 8 + 9, // discriminator + owner + string len + name + score + compression_info
296299
seeds = [b"user_record", user.key().as_ref()],
297300
bump,
298301
)]
@@ -311,7 +314,7 @@ pub struct CreateRecord<'info> {
311314
#[account(
312315
init,
313316
payer = user,
314-
space = 8 + 32 + 4 + 32 + 8, // discriminator + owner + string len + name + score
317+
space = 8 + 32 + 4 + 32 + 8 + 9, // discriminator + owner + string len + name + score + compression_info
315318
seeds = [b"user_record", user.key().as_ref()],
316319
bump,
317320
)]
@@ -407,25 +410,18 @@ impl LightDiscriminator for CompressedAccountVariant {
407410
const LIGHT_DISCRIMINATOR_SLICE: &'static [u8] = &Self::LIGHT_DISCRIMINATOR;
408411
}
409412

410-
impl CompressionTiming for CompressedAccountVariant {
411-
fn last_written_slot(&self) -> u64 {
412-
match self {
413-
Self::UserRecord(data) => data.last_written_slot(),
414-
Self::GameSession(data) => data.last_written_slot(),
415-
}
416-
}
417-
418-
fn compression_delay(&self) -> u64 {
413+
impl HasCompressionInfo for CompressedAccountVariant {
414+
fn compression_info(&self) -> &CompressionInfo {
419415
match self {
420-
Self::UserRecord(data) => data.compression_delay(),
421-
Self::GameSession(data) => data.compression_delay(),
416+
Self::UserRecord(data) => data.compression_info(),
417+
Self::GameSession(data) => data.compression_info(),
422418
}
423419
}
424420

425-
fn set_last_written_slot(&mut self, slot: u64) {
421+
fn compression_info_mut(&mut self) -> &mut CompressionInfo {
426422
match self {
427-
Self::UserRecord(data) => data.set_last_written_slot(slot),
428-
Self::GameSession(data) => data.set_last_written_slot(slot),
423+
Self::UserRecord(data) => data.compression_info_mut(),
424+
Self::GameSession(data) => data.compression_info_mut(),
429425
}
430426
}
431427
}
@@ -440,53 +436,45 @@ pub struct CompressedAccountData {
440436
#[derive(Default, Debug, LightHasher, LightDiscriminator)]
441437
#[account]
442438
pub struct UserRecord {
439+
#[skip]
440+
pub compression_info: CompressionInfo,
443441
#[hash]
444442
pub owner: Pubkey,
445443
pub name: String,
446444
pub score: u64,
447-
pub last_written_slot: u64,
448-
pub compression_delay: u64,
449445
}
450446

451-
impl CompressionTiming for UserRecord {
452-
fn last_written_slot(&self) -> u64 {
453-
self.last_written_slot
454-
}
455-
456-
fn compression_delay(&self) -> u64 {
457-
self.compression_delay
447+
impl HasCompressionInfo for UserRecord {
448+
fn compression_info(&self) -> &CompressionInfo {
449+
&self.compression_info
458450
}
459451

460-
fn set_last_written_slot(&mut self, slot: u64) {
461-
self.last_written_slot = slot;
452+
fn compression_info_mut(&mut self) -> &mut CompressionInfo {
453+
&mut self.compression_info
462454
}
463455
}
464456

465457
#[derive(Default, Debug, LightHasher, LightDiscriminator)]
466458
#[account]
467459
pub struct GameSession {
460+
#[skip]
461+
pub compression_info: CompressionInfo,
468462
pub session_id: u64,
469463
#[hash]
470464
pub player: Pubkey,
471465
pub game_type: String,
472466
pub start_time: u64,
473467
pub end_time: Option<u64>,
474468
pub score: u64,
475-
pub last_written_slot: u64,
476-
pub compression_delay: u64,
477469
}
478470

479-
impl CompressionTiming for GameSession {
480-
fn last_written_slot(&self) -> u64 {
481-
self.last_written_slot
482-
}
483-
484-
fn compression_delay(&self) -> u64 {
485-
self.compression_delay
471+
impl HasCompressionInfo for GameSession {
472+
fn compression_info(&self) -> &CompressionInfo {
473+
&self.compression_info
486474
}
487475

488-
fn set_last_written_slot(&mut self, slot: u64) {
489-
self.last_written_slot = slot;
476+
fn compression_info_mut(&mut self) -> &mut CompressionInfo {
477+
&mut self.compression_info
490478
}
491479
}
492480

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub fn compress_dynamic_pda(
4747
cpi_accounts,
4848
&crate::ID,
4949
rent_recipient,
50-
&config,
50+
&config.compression_delay,
5151
)?;
5252

5353
// any other program logic here...

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use borsh::{BorshDeserialize, BorshSerialize};
22
use light_sdk::{
3-
compressible::{compress_pda_new, CompressibleConfig, CompressionMetadata},
3+
compressible::{compress_pda_new, CompressibleConfig, CompressionInfo},
44
cpi::CpiAccounts,
55
error::LightSdkError,
66
instruction::{PackedAddressTreeInfo, ValidityProof},
@@ -46,8 +46,8 @@ pub fn create_dynamic_pda(
4646
let mut pda_account_data = MyPdaAccount::try_from_slice(&pda_account.data.borrow())
4747
.map_err(|_| LightSdkError::Borsh)?;
4848

49-
// Initialize compression metadata with current slot
50-
pda_account_data.compression_metadata = CompressionMetadata::new()?;
49+
// Initialize compression info with current slot
50+
pda_account_data.compression_info = CompressionInfo::new()?;
5151

5252
compress_pda_new::<MyPdaAccount>(
5353
pda_account,

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use borsh::{BorshDeserialize, BorshSerialize};
22
use light_sdk::{
33
account::LightAccount,
4-
compressible::{decompress_idempotent, CompressionMetadata, HasCompressionMetadata},
4+
compressible::{decompress_idempotent, CompressionInfo, HasCompressionInfo},
55
cpi::CpiAccounts,
66
error::LightSdkError,
77
instruction::{account_meta::CompressedAccountMeta, ValidityProof},
@@ -41,8 +41,6 @@ pub fn decompress_dynamic_pda(
4141
// Extract the data field for use in seeds
4242
let account_data = compressed_account.data;
4343

44-
// Derive the PDA seeds and bump
45-
// In a real implementation, you would pass these as part of the instruction data
4644
// For this example, we'll use the account data as part of the seed
4745
let seeds: &[&[u8]] = &[b"test_pda", &account_data];
4846
let (derived_pda, bump) =
@@ -176,17 +174,18 @@ pub struct MyCompressedAccount {
176174
Clone, Debug, Default, LightHasher, LightDiscriminator, BorshDeserialize, BorshSerialize,
177175
)]
178176
pub struct MyPdaAccount {
179-
pub compression_metadata: CompressionMetadata,
177+
#[skip]
178+
pub compression_info: CompressionInfo,
180179
pub data: [u8; 31],
181180
}
182181

183-
// Implement the HasCompressionMetadata trait
184-
impl HasCompressionMetadata for MyPdaAccount {
185-
fn compression_metadata(&self) -> &CompressionMetadata {
186-
&self.compression_metadata
182+
// Implement the HasCompressionInfo trait
183+
impl HasCompressionInfo for MyPdaAccount {
184+
fn compression_info(&self) -> &CompressionInfo {
185+
&self.compression_info
187186
}
188187

189-
fn compression_metadata_mut(&mut self) -> &mut CompressionMetadata {
190-
&mut self.compression_metadata
188+
fn compression_info_mut(&mut self) -> &mut CompressionInfo {
189+
&mut self.compression_info
191190
}
192191
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ pub async fn decompress_pda(
246246
compressed_account: MyCompressedAccount {
247247
meta,
248248
data: MyPdaAccount {
249-
compression_metadata: light_sdk::compressible::CompressionMetadata::default(),
249+
compression_info: light_sdk::compressible::CompressionInfo::default(),
250250
data: compressed_account
251251
.compressed_account
252252
.data

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

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use crate::{
22
account::LightAccount,
3-
compressible::{metadata::CompressionMetadata, CompressibleConfig},
3+
compressible::{
4+
compression_info::{CompressionInfo, HasCompressionInfo},
5+
CompressibleConfig,
6+
},
47
cpi::{CpiAccounts, CpiInputs},
58
error::LightSdkError,
69
instruction::{account_meta::CompressedAccountMeta, ValidityProof},
@@ -18,12 +21,6 @@ use solana_program_error::ProgramError;
1821
use solana_pubkey::Pubkey;
1922
use solana_sysvar::Sysvar;
2023

21-
/// Trait for accounts that contain CompressionMetadata
22-
pub trait HasCompressionMetadata {
23-
fn compression_metadata(&self) -> &CompressionMetadata;
24-
fn compression_metadata_mut(&mut self) -> &mut CompressionMetadata;
25-
}
26-
2724
/// Helper function to compress a PDA and reclaim rent.
2825
///
2926
/// 1. closes onchain PDA
@@ -41,27 +38,23 @@ pub trait HasCompressionMetadata {
4138
/// * `cpi_accounts` - Accounts needed for CPI
4239
/// * `owner_program` - The program that will own the compressed account
4340
/// * `rent_recipient` - The account to receive the PDA's rent
44-
/// * `config` - The compression config containing delay settings
45-
//
46-
// TODO:
47-
// - check if any explicit checks required for compressed account?
48-
// - consider multiple accounts per ix.
41+
/// * `compression_delay` - The number of slots to wait before compression is allowed
4942
pub fn compress_pda<A>(
5043
pda_account: &AccountInfo,
5144
compressed_account_meta: &CompressedAccountMeta,
5245
proof: ValidityProof,
5346
cpi_accounts: CpiAccounts,
5447
owner_program: &Pubkey,
5548
rent_recipient: &AccountInfo,
56-
config: &CompressibleConfig,
49+
compression_delay: &u32,
5750
) -> Result<(), LightSdkError>
5851
where
5952
A: DataHasher
6053
+ LightDiscriminator
6154
+ BorshSerialize
6255
+ BorshDeserialize
6356
+ Default
64-
+ HasCompressionMetadata,
57+
+ HasCompressionInfo,
6558
{
6659
// Check that the PDA account is owned by the caller program
6760
if pda_account.owner != owner_program {
@@ -75,17 +68,24 @@ where
7568

7669
let current_slot = Clock::get()?.slot;
7770

78-
// Deserialize the PDA data to check timing fields
79-
let pda_data = pda_account.try_borrow_data()?;
80-
let pda_account_data = A::try_from_slice(&pda_data[8..]).map_err(|_| LightSdkError::Borsh)?;
81-
drop(pda_data);
71+
let mut pda_data = pda_account.try_borrow_mut_data()?;
72+
let mut pda_account_data =
73+
A::try_from_slice(&pda_data[8..]).map_err(|_| LightSdkError::Borsh)?;
8274

83-
let last_written_slot = pda_account_data.compression_metadata().last_written_slot();
75+
let last_written_slot = pda_account_data.compression_info().last_written_slot();
76+
77+
// ensure re-init attack is not possible
78+
pda_account_data.compression_info_mut().set_compressed();
79+
80+
pda_account_data
81+
.serialize(&mut &mut pda_data[8..])
82+
.map_err(|_| LightSdkError::Borsh)?;
83+
drop(pda_data);
8484

85-
if current_slot < last_written_slot + config.compression_delay as u64 {
85+
if current_slot < last_written_slot + *compression_delay as u64 {
8686
msg!(
8787
"Cannot compress yet. {} slots remaining",
88-
(last_written_slot + config.compression_delay as u64).saturating_sub(current_slot)
88+
(last_written_slot + *compression_delay as u64).saturating_sub(current_slot)
8989
);
9090
return Err(LightSdkError::ConstraintViolation);
9191
}

0 commit comments

Comments
 (0)