Skip to content

Commit

Permalink
feat: Light SDK without Anchor
Browse files Browse the repository at this point in the history
Provide a possibility to use the Rust Light SDK for programs which are
not using Anchor.

Related changes:

- Rename the former `sdk-test` program to `sdk-anchor-test`.
- Add the new `sdk-test` program, which uses only solana-program.
- Replace all re-imports from `anchor_lang` with direct imports from
  `solana_program`.
- Introduce `anchor` feature flag in `light_sdk`.
- Make the whole `light_sdk::verify` module independent from Anchor.
  • Loading branch information
vadorovsky committed Nov 21, 2024
1 parent bb82a7e commit d9ce1bb
Show file tree
Hide file tree
Showing 40 changed files with 948 additions and 469 deletions.
15 changes: 13 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ members = [
"test-programs/registry-test/",
"test-programs/system-cpi-test/",
"test-programs/system-test/",
"test-programs/sdk-test-program/programs/sdk-test/",
"test-programs/sdk-test/",
"test-programs/sdk-anchor-test/programs/sdk-anchor-test/",
"forester-utils",
"forester",
"photon-api",
Expand Down Expand Up @@ -79,6 +80,7 @@ thiserror = "1.0"
light-client = { path = "client", version = "0.9.1" }
light-concurrent-merkle-tree = { path = "merkle-tree/concurrent", version = "1.1.0" }
light-hasher = { path = "merkle-tree/hasher", version = "1.1.0" }
light-heap = { path = "heap", version = "1.1.0" }
light-indexed-merkle-tree = { path = "merkle-tree/indexed", version = "1.1.0" }
light-macros = { path = "macros/light", version = "1.1.0" }
light-merkle-tree-reference = { path = "merkle-tree/reference", version = "1.1.0" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ anchor-lang = { workspace=true}
borsh = { workspace = true }
light-hasher = { workspace = true, features = ["solana"] }
light-macros = { workspace = true }
light-sdk = { workspace = true }
light-sdk = { workspace = true, features = ["anchor"] }
light-sdk-macros = { workspace = true }
light-utils = { workspace = true }
light-verifier = { workspace = true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use anchor_lang::prelude::*;
use borsh::{BorshDeserialize, BorshSerialize};
use light_hasher::bytes::AsByteVec;
use light_sdk::{
account::LightAccount, instruction_data::LightInstructionData, light_system_accounts,
verify::verify_light_accounts, LightDiscriminator, LightHasher, LightTraits,
account::LightAccount, instruction_data::LightInstructionData, verify::verify_light_accounts,
LightDiscriminator, LightHasher,
};

declare_id!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");
Expand All @@ -15,17 +15,19 @@ pub mod name_service {
use light_hasher::Discriminator;
use light_sdk::{
address::derive_address, error::LightSdkError,
program_merkle_context::unpack_address_merkle_context,
program_merkle_context::unpack_address_merkle_context, system_accounts::LightCpiAccounts,
};

use super::*;

pub fn create_record<'info>(
ctx: Context<'_, '_, '_, 'info, CreateRecord<'info>>,
pub fn create_record<'a, 'b, 'c, 'info>(
ctx: Context<'a, 'b, 'c, 'info, CreateRecord>,
inputs: Vec<u8>,
name: String,
rdata: RData,
) -> Result<()> {
let light_cpi_accounts = LightCpiAccounts::new(ctx.remaining_accounts);

let inputs = LightInstructionData::deserialize(&inputs)?;
let accounts = inputs
.accounts
Expand All @@ -51,20 +53,29 @@ pub mod name_service {
&crate::ID,
)?;

record.owner = ctx.accounts.signer.key();
record.owner = light_cpi_accounts.fee_payer().key.to_owned();
record.name = name;
record.rdata = rdata;

verify_light_accounts(&ctx, inputs.proof, &[record], None, false, None)?;
verify_light_accounts(
&light_cpi_accounts,
inputs.proof,
&[record],
None,
false,
None,
)?;

Ok(())
}

pub fn update_record<'info>(
ctx: Context<'_, '_, '_, 'info, UpdateRecord<'info>>,
ctx: Context<'_, '_, '_, 'info, UpdateRecord>,
inputs: Vec<u8>,
new_rdata: RData,
) -> Result<()> {
let light_cpi_accounts = LightCpiAccounts::new(ctx.remaining_accounts);

// Deserialize the Light Protocol related data.
let inputs = LightInstructionData::deserialize(&inputs)?;
// Require accounts to be provided.
Expand All @@ -78,21 +89,30 @@ pub mod name_service {
LightAccount::from_meta_mut(&accounts[0], NameRecord::discriminator(), &crate::ID)?;

// Check the ownership of the `record`.
if record.owner != ctx.accounts.signer.key() {
if &record.owner != light_cpi_accounts.fee_payer().key {
return err!(CustomError::Unauthorized);
}

record.rdata = new_rdata;

verify_light_accounts(&ctx, inputs.proof, &[record], None, false, None)?;
verify_light_accounts(
&light_cpi_accounts,
inputs.proof,
&[record],
None,
false,
None,
)?;

Ok(())
}

pub fn delete_record<'info>(
ctx: Context<'_, '_, '_, 'info, DeleteRecord<'info>>,
ctx: Context<'_, '_, '_, 'info, DeleteRecord>,
inputs: Vec<u8>,
) -> Result<()> {
let light_cpi_accounts = LightCpiAccounts::new(ctx.remaining_accounts);

let inputs = LightInstructionData::deserialize(&inputs)?;
let accounts = inputs
.accounts
Expand All @@ -102,11 +122,18 @@ pub mod name_service {
let record: LightAccount<'_, NameRecord> =
LightAccount::from_meta_close(&accounts[0], NameRecord::discriminator(), &crate::ID)?;

if record.owner != ctx.accounts.signer.key() {
if &record.owner != light_cpi_accounts.fee_payer().key {
return err!(CustomError::Unauthorized);
}

verify_light_accounts(&ctx, inputs.proof, &[record], None, false, None)?;
verify_light_accounts(
&light_cpi_accounts,
inputs.proof,
&[record],
None,
false,
None,
)?;

Ok(())
}
Expand Down Expand Up @@ -154,41 +181,11 @@ pub enum CustomError {
Unauthorized,
}

#[light_system_accounts]
#[derive(Accounts, LightTraits)]
pub struct CreateRecord<'info> {
#[account(mut)]
#[fee_payer]
pub signer: Signer<'info>,
#[self_program]
pub self_program: Program<'info, crate::program::NameService>,
/// CHECK: Checked in light-system-program.
#[authority]
pub cpi_signer: AccountInfo<'info>,
}
#[derive(Accounts)]
pub struct CreateRecord {}

#[light_system_accounts]
#[derive(Accounts, LightTraits)]
pub struct UpdateRecord<'info> {
#[account(mut)]
#[fee_payer]
pub signer: Signer<'info>,
#[self_program]
pub self_program: Program<'info, crate::program::NameService>,
/// CHECK: Checked in light-system-program.
#[authority]
pub cpi_signer: AccountInfo<'info>,
}
#[derive(Accounts)]
pub struct UpdateRecord {}

#[light_system_accounts]
#[derive(Accounts, LightTraits)]
pub struct DeleteRecord<'info> {
#[account(mut)]
#[fee_payer]
pub signer: Signer<'info>,
#[self_program]
pub self_program: Program<'info, crate::program::NameService>,
/// CHECK: Checked in light-system-program.
#[authority]
pub cpi_signer: AccountInfo<'info>,
}
#[derive(Accounts)]
pub struct DeleteRecord {}
2 changes: 1 addition & 1 deletion examples/name-service/programs/name-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ anchor-lang = { workspace=true}
borsh = { workspace = true }
light-hasher = { workspace = true, features = ["solana"] }
light-macros = { workspace = true }
light-sdk = { workspace = true }
light-sdk = { workspace = true, features = ["anchor"] }
light-sdk-macros = { workspace = true }
light-utils = { workspace = true }
light-verifier = { workspace = true }
Expand Down
2 changes: 1 addition & 1 deletion examples/token-escrow/programs/token-escrow/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ light-system-program = { workspace = true }
account-compression = { workspace = true }
light-hasher = { path = "../../../../merkle-tree/hasher", version = "1.1.0" }
light-verifier = { path = "../../../../circuit-lib/verifier", version = "1.1.0" }
light-sdk = { workspace = true, features = ["legacy"] }
light-sdk = { workspace = true, features = ["anchor", "legacy"] }

[target.'cfg(not(target_os = "solana"))'.dependencies]
solana-sdk = { workspace = true }
Expand Down
4 changes: 2 additions & 2 deletions macros/light-sdk-macros/src/discriminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub(crate) fn discriminator(input: ItemStruct) -> Result<TokenStream> {
let discriminator: proc_macro2::TokenStream = format!("{discriminator:?}").parse().unwrap();

Ok(quote! {
impl #impl_gen light_hasher::Discriminator for #account_name #type_gen #where_clause {
impl #impl_gen light_sdk::hasher::Discriminator for #account_name #type_gen #where_clause {
const DISCRIMINATOR: [u8; 8] = #discriminator;
}
})
Expand All @@ -39,7 +39,7 @@ mod tests {
let output = discriminator(input).unwrap();
let output = output.to_string();

assert!(output.contains("impl light_hasher :: Discriminator for MyAccount"));
assert!(output.contains("impl light_sdk::hasher :: Discriminator for MyAccount"));
assert!(output.contains("[181 , 255 , 112 , 42 , 17 , 188 , 66 , 199]"));
}
}
Loading

0 comments on commit d9ce1bb

Please sign in to comment.