-
Notifications
You must be signed in to change notification settings - Fork 90
refactor: sdk macros 3 #2176
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor: sdk macros 3 #2176
Changes from all commits
be6a5be
a13c83d
237cd24
845590d
1958250
aaccb71
c26d287
3c62e2f
32ec532
623e45d
9c46126
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,6 +56,8 @@ pub struct PackedProofResult { | |
| pub packed_tree_infos: PackedTreeInfos, | ||
| /// Index of output tree in remaining accounts. Pass to instruction data. | ||
| pub output_tree_index: u8, | ||
| /// Index of state merkle tree in remaining accounts (when included for mint creation). | ||
| pub state_tree_index: Option<u8>, | ||
| /// Offset where system accounts start. Pass to instruction data if needed. | ||
| pub system_accounts_offset: u8, | ||
| } | ||
|
|
@@ -81,6 +83,39 @@ pub fn pack_proof( | |
| proof: ValidityProofWithContext, | ||
| output_tree: &TreeInfo, | ||
| cpi_context: Option<Pubkey>, | ||
| ) -> Result<PackedProofResult, PackError> { | ||
| pack_proof_internal(program_id, proof, output_tree, cpi_context, false) | ||
| } | ||
|
|
||
| /// Packs a validity proof with state merkle tree for mint creation. | ||
| /// | ||
| /// Same as `pack_proof` but also includes the state merkle tree in remaining accounts. | ||
| /// This is required for mint creation because the decompress operation needs the state | ||
| /// merkle tree for discriminator validation. | ||
| /// | ||
| /// # Arguments | ||
| /// - `program_id`: Your program's ID | ||
| /// - `proof`: Validity proof from `get_validity_proof()` | ||
| /// - `output_tree`: Tree info for writing outputs (from `get_random_state_tree_info()`) | ||
| /// - `cpi_context`: CPI context pubkey. Required for mint creation. | ||
| /// | ||
| /// # Returns | ||
| /// `PackedProofResult` with `state_tree_index` populated. | ||
| pub fn pack_proof_for_mints( | ||
| program_id: &Pubkey, | ||
| proof: ValidityProofWithContext, | ||
| output_tree: &TreeInfo, | ||
| cpi_context: Option<Pubkey>, | ||
| ) -> Result<PackedProofResult, PackError> { | ||
| pack_proof_internal(program_id, proof, output_tree, cpi_context, true) | ||
| } | ||
|
|
||
| fn pack_proof_internal( | ||
| program_id: &Pubkey, | ||
| proof: ValidityProofWithContext, | ||
| output_tree: &TreeInfo, | ||
| cpi_context: Option<Pubkey>, | ||
| include_state_tree: bool, | ||
| ) -> Result<PackedProofResult, PackError> { | ||
| let mut packed = PackedAccounts::default(); | ||
|
|
||
|
|
@@ -97,7 +132,25 @@ pub fn pack_proof( | |
| .unwrap_or(output_tree.queue); | ||
| let output_tree_index = packed.insert_or_get(output_queue); | ||
|
|
||
| let client_packed_tree_infos = proof.pack_tree_infos(&mut packed); | ||
| // For mint creation: pack address tree first (must be at index 1 per program validation), | ||
| // then state tree. For non-mint: just pack tree infos normally. | ||
| let (client_packed_tree_infos, state_tree_index) = if include_state_tree { | ||
| // Pack tree infos first to ensure address tree is at index 1 | ||
| let tree_infos = proof.pack_tree_infos(&mut packed); | ||
|
|
||
| // Then add state tree (will be after address tree) | ||
| let state_tree = output_tree | ||
| .next_tree_info | ||
| .as_ref() | ||
| .map(|n| n.tree) | ||
| .unwrap_or(output_tree.tree); | ||
| let state_idx = packed.insert_or_get(state_tree); | ||
|
|
||
| (tree_infos, Some(state_idx)) | ||
|
Comment on lines
+135
to
+149
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Clarify the "index 1" comment—it's about ordering, not a literal index. The comment says "address tree must be at index 1" but the actual invariant being enforced is that address trees are packed before the state tree. The actual index depends on prior insertions (system accounts, output queue, etc.). Consider rewording to avoid confusion: - // For mint creation: pack address tree first (must be at index 1 per program validation),
- // then state tree. For non-mint: just pack tree infos normally.
+ // For mint creation: pack address trees before the state tree to ensure deterministic
+ // ordering in remaining accounts. For non-mint: just pack tree infos normally.🤖 Prompt for AI Agents |
||
| } else { | ||
| let tree_infos = proof.pack_tree_infos(&mut packed); | ||
| (tree_infos, None) | ||
| }; | ||
| let (remaining_accounts, system_offset, _) = packed.to_account_metas(); | ||
|
|
||
| // Convert from light_client's types to our local types | ||
|
|
@@ -115,6 +168,7 @@ pub fn pack_proof( | |
| remaining_accounts, | ||
| packed_tree_infos, | ||
| output_tree_index, | ||
| state_tree_index, | ||
| system_accounts_offset: system_offset as u8, | ||
| }) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,23 +14,34 @@ Documentation for the rentfree macro system in `light-sdk-macros`. These macros | |
| | **`rentfree_program/`** | `#[rentfree_program]` attribute macro | | ||
| | **`rentfree_program/architecture.md`** | Architecture overview, usage, generated items | | ||
| | **`rentfree_program/codegen.md`** | Technical implementation details (code generation) | | ||
| | **`traits/`** | Trait derive macros for compressible data structs | | ||
| | **`accounts/`** | Field-level attributes for Accounts structs | | ||
| | **`account/`** | Trait derive macros for account data structs | | ||
|
|
||
| ### Traits Documentation | ||
| ### Accounts Field Attributes | ||
|
|
||
| Field-level attributes applied inside `#[derive(RentFree)]` Accounts structs: | ||
|
|
||
| | File | Attribute | Description | | ||
| |------|-----------|-------------| | ||
| | **`accounts/light_mint.md`** | `#[light_mint(...)]` | Creates compressed mint with automatic decompression | | ||
|
|
||
| See also: `#[rentfree]` attribute documented in `rentfree.md` | ||
|
|
||
| ### Account Trait Documentation | ||
|
|
||
| | File | Macro | Description | | ||
| |------|-------|-------------| | ||
| | **`traits/has_compression_info.md`** | `#[derive(HasCompressionInfo)]` | Accessor methods for compression_info field | | ||
| | **`traits/compress_as.md`** | `#[derive(CompressAs)]` | Creates compressed representation for hashing | | ||
| | **`traits/compressible.md`** | `#[derive(Compressible)]` | Combined: HasCompressionInfo + CompressAs + Size | | ||
| | **`traits/compressible_pack.md`** | `#[derive(CompressiblePack)]` | Pack/Unpack with Pubkey-to-index compression | | ||
| | **`traits/light_compressible.md`** | `#[derive(LightCompressible)]` | All traits for rent-free accounts | | ||
| | **`account/has_compression_info.md`** | `#[derive(HasCompressionInfo)]` | Accessor methods for compression_info field | | ||
| | **`account/compress_as.md`** | `#[derive(CompressAs)]` | Creates compressed representation for hashing | | ||
| | **`account/compressible.md`** | `#[derive(Compressible)]` | Combined: HasCompressionInfo + CompressAs + Size | | ||
| | **`account/compressible_pack.md`** | `#[derive(CompressiblePack)]` | Pack/Unpack with Pubkey-to-index compression | | ||
| | **`account/light_compressible.md`** | `#[derive(LightCompressible)]` | All traits for rent-free accounts | | ||
|
|
||
| ## Navigation Tips | ||
|
|
||
| ### Starting Points | ||
|
|
||
| - **Data struct traits**: Start with `traits/light_compressible.md` for the all-in-one derive macro for compressible data structs | ||
| - **Data struct traits**: Start with `account/light_compressible.md` for the all-in-one derive macro for compressible data structs | ||
| - **Building account structs**: Use `rentfree.md` for the accounts-level derive macro that marks fields for compression | ||
| - **Program-level integration**: Use `rentfree_program/architecture.md` for program-level auto-discovery and instruction generation | ||
| - **Implementation details**: Use `rentfree_program/codegen.md` for technical code generation details | ||
|
|
@@ -52,21 +63,21 @@ Documentation for the rentfree macro system in `light-sdk-macros`. These macros | |
| | | ||
| +-- Generates LightPreInit + LightFinalize impls | ||
| | | ||
| +-- Uses trait derives (traits/): | ||
| - HasCompressionInfo <- traits/has_compression_info.md | ||
| - CompressAs <- traits/compress_as.md | ||
| - Compressible <- traits/compressible.md | ||
| - CompressiblePack <- traits/compressible_pack.md | ||
| - LightCompressible <- traits/light_compressible.md (combines all) | ||
| +-- Uses trait derives (account/): | ||
| - HasCompressionInfo <- account/has_compression_info.md | ||
| - CompressAs <- account/compress_as.md | ||
| - Compressible <- account/compressible.md | ||
| - CompressiblePack <- account/compressible_pack.md | ||
| - LightCompressible <- account/light_compressible.md (combines all) | ||
| ``` | ||
|
|
||
| ## Related Source Code | ||
|
|
||
| ``` | ||
| sdk-libs/macros/src/rentfree/ | ||
| ├── account/ # Trait derive macros for account data structs | ||
| ├── accounts/ # #[derive(RentFree)] implementation | ||
| ├── program/ # #[rentfree_program] implementation | ||
| ├── traits/ # Trait derive macros | ||
| ├── shared_utils.rs # Common utilities | ||
| └── mod.rs # Module exports | ||
|
Comment on lines
76
to
82
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add language specifier to fenced code block. Per static analysis, the code block at line 65 should have a language specifier for proper rendering and syntax highlighting. 📝 Suggested fix-```
+```text
sdk-libs/macros/src/rentfree/
├── account/ # Trait derive macros for account data structs
├── accounts/ # #[derive(RentFree)] implementation
├── program/ # #[rentfree_program] implementation
├── shared_utils.rs # Common utilities
└── mod.rs # Module exports🧰 Tools🪛 markdownlint-cli2 (0.18.1)65-65: Fenced code blocks should have a language specified (MD040, fenced-code-language) 🤖 Prompt for AI Agents |
||
| ``` | ||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -320,6 +320,17 @@ let user_record = packed_record.unpack(ctx.remaining_accounts)?; | |||||||
| - All methods are marked `#[inline(never)]` for smaller program size | ||||||||
| - The packed struct derives `AnchorSerialize` and `AnchorDeserialize` | ||||||||
|
|
||||||||
| ### Limitation: Option<Pubkey> Fields | ||||||||
|
|
||||||||
| Only direct `Pubkey` fields are converted to `u8` indices. `Option<Pubkey>` fields remain as `Option<Pubkey>` in the packed struct because `None` doesn't map cleanly to an index. | ||||||||
|
|
||||||||
| ```rust | ||||||||
| pub struct Record { | ||||||||
| pub owner: Pubkey, // -> u8 in packed struct | ||||||||
| pub delegate: Option<Pubkey>, // -> Option<Pubkey> in packed struct (unchanged) | ||||||||
| } | ||||||||
| ``` | ||||||||
|
|
||||||||
|
Comment on lines
+323
to
+333
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Find relevant documentation and implementation files
echo "=== Finding compressible_pack.md ==="
find . -name "compressible_pack.md" -type f
echo "=== Finding pack_unpack.rs ==="
find . -name "pack_unpack.rs" -type f
echo "=== Finding CLAUDE.md files in macros ==="
find sdk-libs/macros -name "CLAUDE.md" -type fRepository: Lightprotocol/light-protocol Length of output: 344 🏁 Script executed: #!/bin/bash
# Read the documentation file to see the context and Field Handling table
echo "=== compressible_pack.md context (lines 280-340) ==="
sed -n '280,340p' ./sdk-libs/macros/docs/account/compressible_pack.md
echo ""
echo "=== File length and structure ==="
wc -l ./sdk-libs/macros/docs/account/compressible_pack.mdRepository: Lightprotocol/light-protocol Length of output: 2023 🏁 Script executed: #!/bin/bash
# Read the pack_unpack.rs implementation to verify Option<Pubkey> handling
echo "=== pack_unpack.rs full contents ==="
wc -l ./sdk-libs/macros/src/rentfree/account/pack_unpack.rs
echo ""
echo "=== Searching for Option handling ==="
rg -n "Option" ./sdk-libs/macros/src/rentfree/account/pack_unpack.rs
echo ""
echo "=== Searching for Pubkey handling ==="
rg -n -A3 -B3 "Pubkey" ./sdk-libs/macros/src/rentfree/account/pack_unpack.rs | head -100Repository: Lightprotocol/light-protocol Length of output: 244 🏁 Script executed: #!/bin/bash
# Read the actual implementation file
echo "=== pack_unpack.rs full contents ==="
cat -n ./sdk-libs/macros/src/rentfree/account/pack_unpack.rs
echo ""
echo "=== Check for pack/unpack method implementations ==="
rg -n "fn pack|fn unpack" ./sdk-libs/macros/src/rentfree/account/pack_unpack.rsRepository: Lightprotocol/light-protocol Length of output: 7834 🏁 Script executed: #!/bin/bash
# Now check the is_pubkey_type function to see how it handles Option<Pubkey>
echo "=== Finding utils.rs ==="
find ./sdk-libs/macros/src/rentfree/account -name "utils.rs" -type f
echo ""
echo "=== Check utils.rs for is_pubkey_type implementation ==="
cat -n ./sdk-libs/macros/src/rentfree/account/utils.rsRepository: Lightprotocol/light-protocol Length of output: 4769 🏁 Script executed: #!/bin/bash
# Verify the logic by checking what happens with a struct containing Option<Pubkey>
echo "=== Checking if there are any test cases or examples with Option<Pubkey> ==="
rg -n "Option.*Pubkey\|Option<Pubkey>" ./sdk-libs/macros/tests/ --type rust
echo ""
echo "=== Check CLAUDE.md for guidance on macro patterns ==="
cat -n ./sdk-libs/macros/CLAUDE.md | head -50Repository: Lightprotocol/light-protocol Length of output: 2421 🏁 Script executed: #!/bin/bash
# Let me verify the logic flow one more time to be absolutely certain
echo "=== Simulating what happens with Option<Pubkey> ==="
echo "1. is_pubkey_type for Option<Pubkey>:"
echo " - Checks if last path segment is 'Pubkey'"
echo " - Option<Pubkey> has last segment 'Pubkey'? NO, it's the outer Option"
echo " - Result: FALSE"
echo ""
echo "2. is_copy_type for Option<Pubkey>:"
echo " - Checks if type_name == 'Option'"
echo " - has_copy_inner_type checks inner type (Pubkey)"
echo " - Pubkey is in copy list (line 67)"
echo " - Result: TRUE (because Option<Pubkey> inner is copy)"
echo ""
echo "3. Packed field generation (line 32-35):"
echo " - is_pubkey_type = FALSE"
echo " - packed_type = original type = Option<Pubkey>"
echo ""
echo "4. Pack assignment (line 54-62):"
echo " - is_pubkey_type = FALSE"
echo " - is_copy_type = TRUE"
echo " - Uses: self.#field_name (direct copy, line 59)"
echo ""
echo "5. Unpack assignment (line 109-118):"
echo " - is_pubkey_type = FALSE"
echo " - is_copy_type = TRUE"
echo " - Uses: self.#field_name (direct copy, line 114)"Repository: Lightprotocol/light-protocol Length of output: 920 Add The new limitation section correctly documents that
This brings the table in line with the documented behavior where The example would also benefit from showing the generated 🤖 Prompt for AI Agents |
||||||||
| --- | ||||||||
|
|
||||||||
| ## 10. Related Macros | ||||||||
|
|
||||||||
Uh oh!
There was an error while loading. Please reload this page.