Skip to content

Conversation

@ananas-block
Copy link
Contributor

@ananas-block ananas-block commented Jan 24, 2026

  1. Split single discriminator macro into two separate macros
    • light_discriminator() function: SHA256("{name}")[0..8]
    • anchor_discriminator() function: SHA256("account:{name}")[0..8]
  2. Add AnchorDiscriminator derive macro export (light-sdk-macros)
    - New proc_macro_derive attribute with documentation
  3. Update macro function references
    - light_hasher.rs: Changed 2 references from discriminator() to light_discriminator()
    - light_compressible.rs: Changed import and function call to light_discriminator()
  4. Remove anchor-discriminator feature flag from 3 packages
    - sdk-libs/macros/Cargo.toml
    - sdk-libs/compressed-token-sdk/Cargo.toml
    - sdk-libs/sdk/Cargo.toml
  5. Add AnchorDiscriminator re-export to SDK packages
    - light-sdk/src/lib.rs: Export from light_sdk_macros
    - light-token/src/anchor.rs: Export from light_sdk_macros
  6. Remove anchor-discriminator feature from 5 test packages
    - Remove from light-sdk dependency features in all 5 sdk-tests packages
  7. Update test structs to use AnchorDiscriminator
    - light_account_sha.rs: Changed from LightDiscriminator to AnchorDiscriminator
    - light_account_poseidon.rs: Changed from LightDiscriminator to AnchorDiscriminator
  8. Update hardcoded discriminator values in tests
    - TEST_SHA_DISCRIMINATOR: [57, 91, 172, 77, ...] → [133, 206, 241, 201, ...]
    - TEST_POSEIDON_DISCRIMINATOR: [174, 23, 156, 239, ...] → [250, 202, 237, 234, ...]
  9. Add new discriminator.rs test file
    - 5 tests verifying both LightDiscriminator and AnchorDiscriminator formats and values
  10. Add unit tests for discriminator macros (discriminator.rs)
    - test_light_discriminator: Verify SHA256("{name}") format
    - test_anchor_discriminator: Verify SHA256("account:{name}") format

Summary by CodeRabbit

Release Notes

  • New Features

    • Added AnchorDiscriminator derive macro as an alternative discriminator implementation alongside LightDiscriminator.
  • Tests

    • Added comprehensive test suites covering address derivation, discriminator functionality, account implementations, and token instruction handling.
  • Chores

    • Removed anchor-discriminator feature flag; functionality now available via explicit AnchorDiscriminator macro.
    • Refactored discriminator macro organization and naming for clarity.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 24, 2026

📝 Walkthrough

Walkthrough

This PR refactors the discriminator system by removing the conditional anchor-discriminator feature flag and establishing it as a standalone macro. The discriminator macro is renamed to light_discriminator, while a new anchor_discriminator function is introduced. Derive macro names are updated to avoid collisions (light_discriminator_derive and anchor_discriminator_derive). Extensive test suites are added for discriminators, address derivation, and account functionality.

Changes

Cohort / File(s) Summary
Feature removal: anchor-discriminator
sdk-libs/compressed-token-sdk/Cargo.toml, sdk-libs/macros/Cargo.toml, sdk-libs/sdk/Cargo.toml, sdk-libs/token-sdk/Cargo.toml
Removes anchor-discriminator feature declaration and resets default features to [], consolidating feature management and making anchor discriminator non-optional.
Discriminator macro refactoring
sdk-libs/macros/src/discriminator.rs, sdk-libs/macros/src/lib.rs
Renames discriminatorlight_discriminator, adds separate anchor_discriminator function, and renames derive macros to light_discriminator_derive and anchor_discriminator_derive to prevent naming conflicts.
Discriminator usage updates
sdk-libs/compressed-token-sdk/src/lib.rs, sdk-libs/macros/src/hasher/light_hasher.rs, sdk-libs/macros/src/light_pdas/account/light_compressible.rs, sdk-libs/sdk/src/lib.rs, sdk-libs/token-sdk/src/anchor.rs
Updates imports, macro calls, and public re-exports to reflect renamed discriminator functions and adds AnchorDiscriminator to public exports.
SDK Cargo.toml adjustments
sdk-libs/sdk/Cargo.toml
Expands dev-dependency feature sets for light-compressed-account and light-hasher with additional hash algorithm support (sha256, poseidon).
Discriminator tests
sdk-libs/sdk/tests/discriminator.rs
New test suite validating LightDiscriminator and AnchorDiscriminator derive macros with hardcoded SHA-256 values and verifying discriminator consistency across trait methods.
Address derivation test suites
sdk-libs/sdk/tests/address_derivation.rs, sdk-libs/token-sdk/tests/address_derivation.rs
Comprehensive regression tests for v1/v2 address seed derivation and ATA/SPL PDA derivation with edge cases and cross-version consistency checks.
LightAccount test suites
sdk-libs/sdk/tests/light_account_sha.rs, sdk-libs/sdk/tests/light_account_poseidon.rs
Full test coverage for LightAccount construction, conversion, and accessor methods across SHA256 and Poseidon hash variants.
Token SDK instruction & behavior tests
sdk-libs/token-sdk/tests/instruction_close.rs, sdk-libs/token-sdk/tests/instruction_transfer.rs, sdk-libs/token-sdk/tests/transfer_type.rs, sdk-libs/token-sdk/tests/constants_regression.rs, sdk-libs/token-sdk/tests/error_codes.rs
New test modules validating instruction construction, transfer type determination, program constants, and error code stability.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

ai-review, feature-flag-removal, macro-refactor, testing

Suggested reviewers

  • sergeytimoshin
  • SwenSchaeferjohann

Poem

🔑 From feature flags to standalone macros bright,
Light and Anchor discriminators now unite,
Derives renamed to dance without a fight,
Tests bloom across the suite—everything's tight!
🎯

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: splitting the discriminator macro into two separate implementations and exposing AnchorDiscriminator as a distinct export.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 70.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jorrit/test-sdk

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@sdk-libs/sdk/tests/discriminator.rs`:
- Around line 46-62: Add an inline comment in the
test_discriminators_are_different test that documents the concrete discriminator
outputs for clarity: reference TestAccount::LIGHT_DISCRIMINATOR and
TestAccountAnchor::LIGHT_DISCRIMINATOR and show (as comment-only examples) the
computed formats SHA256("TestAccount")[0..8] -> <light value> and
SHA256("account:TestAccount")[0..8] -> <anchor value> so readers can immediately
see the differing byte sequences without changing test logic; place this comment
near the existing explanation lines about the differing formats.

In `@sdk-libs/sdk/tests/light_account_poseidon.rs`:
- Around line 540-584: Add a parallel test in the SHA suite that mirrors the
Poseidon test: create a TestShaAccount instance, build a
LightAccount::<TestShaAccount> via new_mut with a
PackedStateTreeInfo/CompressedAccountMeta (matching the Poseidon test setup),
call remove_data() on the account, convert it to OutAccountInfo via
to_account_info(), extract output and assert equality with an expected
OutAccountInfo where discriminator and data_hash are zeroed (and
output_merkle_tree_index, lamports, data match the Poseidon expectations). Name
the test similarly (e.g., test_remove_data_sha) and reuse the same symbols:
LightAccount, remove_data, to_account_info, OutAccountInfo, and TestShaAccount
to ensure parity between light_account_poseidon.rs and light_account_sha.rs.

In `@sdk-libs/token-sdk/tests/error_codes.rs`:
- Around line 44-48: Remove the redundant test
test_spl_interface_required_is_17500 because its assertion that
LightTokenError::SplInterfaceRequired maps to 17500 is already covered by
test_error_codes_start_at_17500; either delete the entire
test_spl_interface_required_is_17500 function or merge any unique intent into
test_error_codes_start_at_17500 so the mapping for
LightTokenError::SplInterfaceRequired remains asserted only once.

Comment on lines +46 to +62
#[test]
fn test_discriminators_are_different() {
// Light format: SHA256("TestAccount")[0..8]
let light_discriminator = TestAccount::LIGHT_DISCRIMINATOR;

// Anchor format: SHA256("account:TestAccountAnchor")[0..8]
// Note: We can't derive both on the same struct, so we use a different struct name
// The key is that even if we manually computed SHA256("account:TestAccount"),
// it would differ from SHA256("TestAccount")
let anchor_discriminator = TestAccountAnchor::LIGHT_DISCRIMINATOR;

// Verify they're different (even though they have similar names)
assert_ne!(
light_discriminator, anchor_discriminator,
"Light and Anchor discriminators should produce different values"
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Good documentation of the test limitation.

The comment on lines 52-54 correctly explains why we can't derive both discriminator types on the same struct—both macros implement LightDiscriminator, so you'd get a trait conflict. The test serves as a sanity check that both macros work and produce different outputs, while the hardcoded value tests above actually verify the format correctness.

Consider adding a comment-based assertion showing what the Anchor format would produce for "account:TestAccount" to make the format difference more explicit:

// For reference:
// SHA256("TestAccount")[0..8] produces: light_discriminator
// SHA256("account:TestAccount")[0..8] would produce: [different value]
🤖 Prompt for AI Agents
In `@sdk-libs/sdk/tests/discriminator.rs` around lines 46 - 62, Add an inline
comment in the test_discriminators_are_different test that documents the
concrete discriminator outputs for clarity: reference
TestAccount::LIGHT_DISCRIMINATOR and TestAccountAnchor::LIGHT_DISCRIMINATOR and
show (as comment-only examples) the computed formats SHA256("TestAccount")[0..8]
-> <light value> and SHA256("account:TestAccount")[0..8] -> <anchor value> so
readers can immediately see the differing byte sequences without changing test
logic; place this comment near the existing explanation lines about the
differing formats.

Comment on lines +540 to +584
/// Test remove_data functionality.
#[test]
fn test_remove_data() {
let program_id = Pubkey::new_from_array([2u8; 32]);
let tree_info = PackedStateTreeInfo {
root_index: 0,
prove_by_index: false,
merkle_tree_pubkey_index: 0,
queue_pubkey_index: 1,
leaf_index: 100,
};
let account_meta = CompressedAccountMeta {
tree_info,
address: [3u8; 32],
output_state_tree_index: 0,
};

let mut account = LightAccount::<TestPoseidonAccount>::new_mut(
&program_id,
&account_meta,
TestPoseidonAccount::default(),
)
.expect("Failed to create LightAccount");

account.remove_data();

let account_info = account
.to_account_info()
.expect("Should convert to account info");

let output = account_info.output.expect("Should have output");

// After remove_data, output should have zeroed hash and discriminator
let expected_output = OutAccountInfo {
discriminator: [0u8; 8],
data_hash: [0u8; 32],
output_merkle_tree_index: 0,
lamports: 0,
data: vec![],
};
assert_eq!(
output, expected_output,
"Output after remove_data should have zeroed data_hash and discriminator"
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

remove_data test provides useful coverage.

This test verifies that remove_data() zeroes both the discriminator and data_hash in the output. Consider adding an equivalent test to light_account_sha.rs for parity between the test suites.

🤖 Prompt for AI Agents
In `@sdk-libs/sdk/tests/light_account_poseidon.rs` around lines 540 - 584, Add a
parallel test in the SHA suite that mirrors the Poseidon test: create a
TestShaAccount instance, build a LightAccount::<TestShaAccount> via new_mut with
a PackedStateTreeInfo/CompressedAccountMeta (matching the Poseidon test setup),
call remove_data() on the account, convert it to OutAccountInfo via
to_account_info(), extract output and assert equality with an expected
OutAccountInfo where discriminator and data_hash are zeroed (and
output_merkle_tree_index, lamports, data match the Poseidon expectations). Name
the test similarly (e.g., test_remove_data_sha) and reuse the same symbols:
LightAccount, remove_data, to_account_info, OutAccountInfo, and TestShaAccount
to ensure parity between light_account_poseidon.rs and light_account_sha.rs.

Comment on lines +44 to +48
#[test]
fn test_spl_interface_required_is_17500() {
let code: u32 = LightTokenError::SplInterfaceRequired.into();
assert_eq!(code, 17500, "SplInterfaceRequired must be 17500");
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Minor: Redundant test case.

test_spl_interface_required_is_17500 duplicates the assertion already made in test_error_codes_start_at_17500 (lines 10-17). Consider removing this test or consolidating them.

♻️ Suggested consolidation
-#[test]
-fn test_spl_interface_required_is_17500() {
-    let code: u32 = LightTokenError::SplInterfaceRequired.into();
-    assert_eq!(code, 17500, "SplInterfaceRequired must be 17500");
-}

The test_error_codes_start_at_17500 test already verifies this exact assertion.

📝 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
#[test]
fn test_spl_interface_required_is_17500() {
let code: u32 = LightTokenError::SplInterfaceRequired.into();
assert_eq!(code, 17500, "SplInterfaceRequired must be 17500");
}
🤖 Prompt for AI Agents
In `@sdk-libs/token-sdk/tests/error_codes.rs` around lines 44 - 48, Remove the
redundant test test_spl_interface_required_is_17500 because its assertion that
LightTokenError::SplInterfaceRequired maps to 17500 is already covered by
test_error_codes_start_at_17500; either delete the entire
test_spl_interface_required_is_17500 function or merge any unique intent into
test_error_codes_start_at_17500 so the mapping for
LightTokenError::SplInterfaceRequired remains asserted only once.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants