Skip to content

Commit

Permalink
feat: New instruction format (#1288)
Browse files Browse the repository at this point in the history
  • Loading branch information
vadorovsky authored Nov 12, 2024
1 parent 93afef4 commit 1e40cc4
Show file tree
Hide file tree
Showing 24 changed files with 1,898 additions and 658 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/light-examples-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ jobs:
sub-tests: '[
"cargo test-sbf -p token-escrow -- --test-threads=1"
]'
- program: name-service-test
- program: name-service-without-macros-test
sub-tests: '[
"cargo test-sbf -p name-service -- --test-threads=1"
"cargo test-sbf -p name-service-without-macros -- --test-threads=1"
]'

steps:
Expand Down
8 changes: 7 additions & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ jobs:
run: |
source ./scripts/devenv.sh
echo "Rust version: $(rustc --version)"
RUST_MIN_STACK=8388608 RUSTFLAGS="-D warnings" cargo test --all-targets --workspace --exclude light-concurrent-merkle-tree --exclude photon-api --exclude forester
RUST_MIN_STACK=8388608 RUSTFLAGS="-D warnings" \
cargo test --all-targets --workspace \
--exclude light-concurrent-merkle-tree \
--exclude photon-api \
--exclude forester \
--exclude name-service \
--exclude mixed-accounts
- name: Test light-concurrent-merkle-tree
run: |
Expand Down
19 changes: 19 additions & 0 deletions Cargo.lock

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
@@ -0,0 +1,40 @@
[package]
name = "name-service-without-macros"
version = "0.7.0"
description = "Created with Anchor"
edition = "2021"
rust-version = "1.75.0"
license = "Apache-2.0"

[lib]
crate-type = ["cdylib", "lib"]
name = "name_service_without_macros"

[features]
no-entrypoint = []
no-idl = []
no-log-ix-name = []
cpi = ["no-entrypoint"]
default = ["idl-build"]
test-sbf = []
bench-sbf = []
idl-build = ["anchor-lang/idl-build", "light-sdk/idl-build"]

[dependencies]
anchor-lang = { workspace=true}
borsh = { workspace = true }
light-hasher = { workspace = true, features = ["solana"] }
light-macros = { workspace = true }
light-sdk = { workspace = true }
light-sdk-macros = { workspace = true }
light-utils = { workspace = true }
light-verifier = { workspace = true }

[target.'cfg(not(target_os = "solana"))'.dependencies]
solana-sdk = { workspace = true }

[dev-dependencies]
light-client = { workspace = true , features = ["devenv"]}
light-test-utils = { path = "../../../../test-utils", version = "1.2.0", features = ["devenv"] }
solana-program-test = { workspace = true }
tokio = "1.36.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []
194 changes: 194 additions & 0 deletions examples/name-service/programs/name-service-without-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
use std::net::{Ipv4Addr, Ipv6Addr};

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,
};

declare_id!("7yucc7fL3JGbyMwg4neUaenNSdySS39hbAk89Ao3t1Hz");

#[program]
pub mod name_service {
use light_hasher::Discriminator;
use light_sdk::{
address::derive_address, error::LightSdkError,
program_merkle_context::unpack_address_merkle_context,
};

use super::*;

pub fn create_record<'info>(
ctx: Context<'_, '_, '_, 'info, CreateRecord<'info>>,
inputs: Vec<u8>,
name: String,
rdata: RData,
) -> Result<()> {
let inputs = LightInstructionData::deserialize(&inputs)?;
let accounts = inputs
.accounts
.as_ref()
.ok_or(LightSdkError::ExpectedAccounts)?;

let address_merkle_context = accounts[0]
.address_merkle_context
.ok_or(LightSdkError::ExpectedAddressMerkleContext)?;
let address_merkle_context =
unpack_address_merkle_context(address_merkle_context, ctx.remaining_accounts);
let (address, address_seed) = derive_address(
&[b"name-service", name.as_bytes()],
&address_merkle_context,
&crate::ID,
);

let mut record: LightAccount<'_, NameRecord> = LightAccount::from_meta_init(
&accounts[0],
NameRecord::discriminator(),
address,
address_seed,
&crate::ID,
)?;

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

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

Ok(())
}

pub fn update_record<'info>(
ctx: Context<'_, '_, '_, 'info, UpdateRecord<'info>>,
inputs: Vec<u8>,
new_rdata: RData,
) -> Result<()> {
// Deserialize the Light Protocol related data.
let inputs = LightInstructionData::deserialize(&inputs)?;
// Require accounts to be provided.
let accounts = inputs
.accounts
.as_ref()
.ok_or(LightSdkError::ExpectedAccounts)?;

// Convert `LightAccountMeta` to `LightAccount`.
let mut record: LightAccount<'_, NameRecord> =
LightAccount::from_meta_mut(&accounts[0], NameRecord::discriminator(), &crate::ID)?;

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

record.rdata = new_rdata;

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

Ok(())
}

pub fn delete_record<'info>(
ctx: Context<'_, '_, '_, 'info, DeleteRecord<'info>>,
inputs: Vec<u8>,
) -> Result<()> {
let inputs = LightInstructionData::deserialize(&inputs)?;
let accounts = inputs
.accounts
.as_ref()
.ok_or(LightSdkError::ExpectedAccounts)?;

let record: LightAccount<'_, NameRecord> =
LightAccount::from_meta_close(&accounts[0], NameRecord::discriminator(), &crate::ID)?;

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

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

Ok(())
}
}

#[derive(Clone, Debug, Eq, PartialEq, BorshDeserialize, BorshSerialize)]
pub enum RData {
A(Ipv4Addr),
AAAA(Ipv6Addr),
CName(String),
}

impl anchor_lang::IdlBuild for RData {}

impl AsByteVec for RData {
fn as_byte_vec(&self) -> Vec<Vec<u8>> {
match self {
Self::A(ipv4_addr) => vec![ipv4_addr.octets().to_vec()],
Self::AAAA(ipv6_addr) => vec![ipv6_addr.octets().to_vec()],
Self::CName(cname) => cname.as_byte_vec(),
}
}
}

impl Default for RData {
fn default() -> Self {
Self::A(Ipv4Addr::new(127, 0, 0, 1))
}
}

#[derive(
Clone, Debug, Default, AnchorDeserialize, AnchorSerialize, LightDiscriminator, LightHasher,
)]
pub struct NameRecord {
#[truncate]
pub owner: Pubkey,
#[truncate]
pub name: String,
pub rdata: RData,
}

#[error_code]
pub enum CustomError {
#[msg("No authority to perform this action")]
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>,
}

#[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>,
}

#[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>,
}
Loading

0 comments on commit 1e40cc4

Please sign in to comment.