Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions sdk-libs/compressed-token-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@ license = "Apache-2.0"
repository = "https://github.com/Lightprotocol/light-protocol"

[features]
default = ["anchor-discriminator"]
default = []
v1 = []
anchor-discriminator = ["light-sdk/anchor-discriminator"]
anchor = ["anchor-lang", "light-token-types/anchor", "light-token-interface/anchor"]
# idl-build feature enables IDL generation for client-side tooling and SDK generation
idl-build = ["anchor", "anchor-lang/idl-build", "light-sdk/idl-build"]
Expand Down
1 change: 0 additions & 1 deletion sdk-libs/compressed-token-sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
//!
//! - `v1` - Enable v1 compressed token support
//! - `anchor` - Enable Anchor framework integration
//! - `anchor-discriminator` - Use Anchor-style discriminators (default)
//!
//! ## Modules
//!
Expand Down
1 change: 0 additions & 1 deletion sdk-libs/macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ edition = "2021"


[features]
anchor-discriminator = []

[dependencies]
proc-macro2 = { workspace = true }
Expand Down
64 changes: 52 additions & 12 deletions sdk-libs/macros/src/discriminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ use proc_macro2::TokenStream;
use quote::quote;
use syn::{ItemStruct, Result};

pub(crate) fn discriminator(input: ItemStruct) -> Result<TokenStream> {
/// Light discriminator: SHA256("{name}")[0..8]
/// Implements LightDiscriminator trait
pub(crate) fn light_discriminator(input: ItemStruct) -> Result<TokenStream> {
let account_name = &input.ident;
// When anchor-discriminator-compat feature is enabled, use "account:" prefix like Anchor does
#[cfg(feature = "anchor-discriminator")]
let hash_input = format!("account:{}", account_name);

#[cfg(not(feature = "anchor-discriminator"))]
let hash_input = account_name.to_string();

let (impl_gen, type_gen, where_clause) = input.generics.split_for_impl();
Expand All @@ -30,16 +27,58 @@ pub(crate) fn discriminator(input: ItemStruct) -> Result<TokenStream> {
})
}

/// Anchor discriminator: SHA256("account:{name}")[0..8]
/// Implements the SAME LightDiscriminator trait, just with different hash input
pub(crate) fn anchor_discriminator(input: ItemStruct) -> Result<TokenStream> {
let account_name = &input.ident;
let hash_input = format!("account:{}", account_name);

let (impl_gen, type_gen, where_clause) = input.generics.split_for_impl();

let mut discriminator = [0u8; 8];
discriminator.copy_from_slice(&Sha256::hash(hash_input.as_bytes()).unwrap()[..8]);
let discriminator: proc_macro2::TokenStream = format!("{discriminator:?}").parse().unwrap();

// Same trait, different value
Ok(quote! {
impl #impl_gen LightDiscriminator for #account_name #type_gen #where_clause {
const LIGHT_DISCRIMINATOR: [u8; 8] = #discriminator;
const LIGHT_DISCRIMINATOR_SLICE: &'static [u8] = &Self::LIGHT_DISCRIMINATOR;

fn discriminator() -> [u8; 8] {
Self::LIGHT_DISCRIMINATOR
}
}
})
}

#[cfg(test)]
mod tests {
use syn::parse_quote;

use super::*;

#[cfg(not(feature = "anchor-discriminator"))]
#[test]
fn test_discriminator() {
use syn::parse_quote;
fn test_light_discriminator() {
let input: ItemStruct = parse_quote! {
struct MyAccount {
a: u32,
b: i32,
c: u64,
d: i64,
}
};

use super::*;
let output = light_discriminator(input).unwrap();
let output = output.to_string();

assert!(output.contains("impl LightDiscriminator for MyAccount"));
// SHA256("MyAccount")[0..8]
assert!(output.contains("[181 , 255 , 112 , 42 , 17 , 188 , 66 , 199]"));
}

#[test]
fn test_anchor_discriminator() {
let input: ItemStruct = parse_quote! {
struct MyAccount {
a: u32,
Expand All @@ -49,10 +88,11 @@ mod tests {
}
};

let output = discriminator(input).unwrap();
let output = anchor_discriminator(input).unwrap();
let output = output.to_string();

assert!(output.contains("impl LightDiscriminator for MyAccount"));
assert!(output.contains("[181 , 255 , 112 , 42 , 17 , 188 , 66 , 199]"));
// SHA256("account:MyAccount")[0..8] = f6 1c 06 57 fb 2d 32 2a
assert!(output.contains("[246 , 28 , 6 , 87 , 251 , 45 , 50 , 42]"));
}
}
4 changes: 2 additions & 2 deletions sdk-libs/macros/src/hasher/light_hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ impl ::light_hasher::DataHasher for OuterStruct {
"SHA256 hasher should work with large structs"
);

let sha_discriminator_result = crate::discriminator::discriminator(input.clone());
let sha_discriminator_result = crate::discriminator::light_discriminator(input.clone());
assert!(
sha_discriminator_result.is_ok(),
"SHA256 discriminator should work with large structs"
Expand Down Expand Up @@ -736,7 +736,7 @@ impl ::light_hasher::DataHasher for OuterStruct {
"SHA256 hasher must handle complex real-world structs"
);

let sha_discriminator_result = crate::discriminator::discriminator(input.clone());
let sha_discriminator_result = crate::discriminator::light_discriminator(input.clone());
assert!(
sha_discriminator_result.is_ok(),
"SHA256 discriminator must handle complex real-world structs"
Expand Down
46 changes: 43 additions & 3 deletions sdk-libs/macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
extern crate proc_macro;
use discriminator::discriminator;
use discriminator::{anchor_discriminator, light_discriminator};
use hasher::{derive_light_hasher, derive_light_hasher_sha};
use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput, ItemStruct};
Expand All @@ -15,10 +15,50 @@ mod utils;
#[cfg(test)]
mod light_pdas_tests;

/// Derives a discriminator using SHA256("{struct_name}")[0..8].
///
/// This is the Light Protocol native discriminator format.
/// Use this for new Light Protocol accounts that don't need Anchor compatibility.
///
/// ## Example
///
/// ```ignore
/// use light_sdk::LightDiscriminator;
///
/// #[derive(LightDiscriminator)]
/// pub struct MyAccount {
/// pub owner: Pubkey,
/// pub counter: u64,
/// }
/// // MyAccount::LIGHT_DISCRIMINATOR = SHA256("MyAccount")[0..8]
/// ```
#[proc_macro_derive(LightDiscriminator)]
pub fn light_discriminator(input: TokenStream) -> TokenStream {
pub fn light_discriminator_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemStruct);
into_token_stream(light_discriminator(input))
}

/// Derives a discriminator using SHA256("account:{struct_name}")[0..8].
///
/// This is the Anchor-compatible discriminator format.
/// Use this when you need compatibility with Anchor's account discriminator format.
///
/// ## Example
///
/// ```ignore
/// use light_sdk::AnchorDiscriminator;
///
/// #[derive(AnchorDiscriminator)]
/// pub struct MyAccount {
/// pub owner: Pubkey,
/// pub counter: u64,
/// }
/// // MyAccount::LIGHT_DISCRIMINATOR = SHA256("account:MyAccount")[0..8]
/// ```
#[proc_macro_derive(AnchorDiscriminator)]
pub fn anchor_discriminator_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemStruct);
into_token_stream(discriminator(input))
into_token_stream(anchor_discriminator(input))
}

/// Makes the annotated struct hashable by implementing the following traits:
Expand Down
4 changes: 2 additions & 2 deletions sdk-libs/macros/src/light_pdas/account/light_compressible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use quote::quote;
use syn::{DeriveInput, Fields, ItemStruct, Result};

use crate::{
discriminator::discriminator,
discriminator::light_discriminator,
hasher::derive_light_hasher_sha,
light_pdas::account::{pack_unpack::derive_compressible_pack, traits::derive_compressible},
};
Expand Down Expand Up @@ -61,7 +61,7 @@ pub fn derive_light_account(input: DeriveInput) -> Result<TokenStream> {
let hasher_impl = derive_light_hasher_sha(item_struct.clone())?;

// Generate LightDiscriminator implementation
let discriminator_impl = discriminator(item_struct)?;
let discriminator_impl = light_discriminator(item_struct)?;

// Generate Compressible implementation (HasCompressionInfo + CompressAs + Size + CompressedInitSpace)
let compressible_impl = derive_compressible(input.clone())?;
Expand Down
5 changes: 2 additions & 3 deletions sdk-libs/sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ poseidon = ["light-hasher/poseidon", "light-compressed-account/poseidon"]
keccak = ["light-hasher/keccak", "light-compressed-account/keccak"]
sha256 = ["light-hasher/sha256", "light-compressed-account/sha256"]
merkle-tree = ["light-concurrent-merkle-tree/solana"]
anchor-discriminator = ["light-sdk-macros/anchor-discriminator"]
custom-heap = ["light-heap"]

[dependencies]
Expand Down Expand Up @@ -62,8 +61,8 @@ light-heap = { workspace = true, optional = true }

[dev-dependencies]
num-bigint = { workspace = true }
light-compressed-account = { workspace = true, features = ["new-unique"] }
light-hasher = { workspace = true, features = ["keccak"] }
light-compressed-account = { workspace = true, features = ["new-unique", "sha256", "poseidon"] }
light-hasher = { workspace = true, features = ["keccak", "sha256", "poseidon"] }
anchor-lang = { workspace = true }

[lints.rust.unexpected_cfgs]
Expand Down
4 changes: 2 additions & 2 deletions sdk-libs/sdk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ pub extern crate light_hasher;
use light_hasher::DataHasher;
pub use light_macros::{derive_light_cpi_signer, derive_light_cpi_signer_pda};
pub use light_sdk_macros::{
derive_light_rent_sponsor, derive_light_rent_sponsor_pda, LightDiscriminator, LightHasher,
LightHasherSha,
derive_light_rent_sponsor, derive_light_rent_sponsor_pda, AnchorDiscriminator,
LightDiscriminator, LightHasher, LightHasherSha,
};
pub use light_sdk_types::{constants, instruction::PackedAddressTreeInfoExt, CpiSigner};
use solana_account_info::AccountInfo;
Expand Down
Loading
Loading