Skip to content

Commit

Permalink
Add prototyping comments
Browse files Browse the repository at this point in the history
  • Loading branch information
lorisleiva committed Jan 7, 2025
1 parent e6f8433 commit c908dd2
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 24 deletions.
8 changes: 6 additions & 2 deletions program/src/assertions.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{error::CounterError, state::Key};
use crate::{error::CounterError, state::AccountDiscriminator};
use solana_program::{
account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError,
pubkey::Pubkey,
Expand Down Expand Up @@ -161,7 +161,11 @@ pub fn assert_same_pubkeys(
}

/// Assert that the given account has the expected account key.
pub fn assert_account_key(account_name: &str, account: &AccountInfo, key: Key) -> ProgramResult {
pub fn assert_account_key(
account_name: &str,
account: &AccountInfo,
key: AccountDiscriminator,
) -> ProgramResult {
let key_number = key as u8;
if account.data_len() <= 1 || account.try_borrow_data()?[0] != key_number {
msg!(
Expand Down
6 changes: 6 additions & 0 deletions program/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,10 @@ pub enum CounterInstruction {
#[account(2, writable, signer, name="payer", desc = "The account paying for the storage fees")]
#[account(3, name="system_program", desc = "The system program")]
Create,
// Write (Includes resize)
// InitializeCanonical (Write before on same account)
// InitializeThirdParty (Write before on same account)
// Update (Write before on external Buffer account)
// Set authority (for canonical only)
// Close
}
12 changes: 6 additions & 6 deletions program/src/processor/create.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
assertions::{assert_pda, assert_same_pubkeys, assert_signer, assert_writable},
instruction::accounts::CreateAccounts,
state::{Counter, Key},
state::{AccountDiscriminator, Metadata},
utils::create_account,
};
use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, system_program};
Expand All @@ -15,7 +15,7 @@ pub fn create<'a>(accounts: &'a [AccountInfo<'a>]) -> ProgramResult {
"counter",
ctx.accounts.counter,
&crate::ID,
&Counter::seeds(ctx.accounts.authority.key),
&Metadata::seeds(ctx.accounts.authority.key),
)?;
assert_signer("authority", ctx.accounts.authority)?;
assert_signer("payer", ctx.accounts.payer)?;
Expand All @@ -32,19 +32,19 @@ pub fn create<'a>(accounts: &'a [AccountInfo<'a>]) -> ProgramResult {
}

// Create Counter PDA.
let counter = Counter {
key: Key::Counter,
let counter = Metadata {
discriminator: AccountDiscriminator::Counter,
authority: *ctx.accounts.authority.key,
value: 0,
};
let mut seeds = Counter::seeds(ctx.accounts.authority.key);
let mut seeds = Metadata::seeds(ctx.accounts.authority.key);
let bump = [counter_bump];
seeds.push(&bump);
create_account(
ctx.accounts.counter,
ctx.accounts.payer,
ctx.accounts.system_program,
Counter::LEN,
Metadata::LEN,
&crate::ID,
Some(&[&seeds]),
)?;
Expand Down
115 changes: 99 additions & 16 deletions program/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,68 @@ use solana_program::pubkey::Pubkey;

use crate::error::CounterError;

#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)]
pub enum Key {
Uninitialized,
Counter,
}
// Canonical + Authority x and program_authority allowed to update Metadata
// -> [authority = Some(x)] [mutable = true] [canonical = true]
// Canonical + Only program_authority allowed to update Metadata (Could end up immutable as well)
// -> [authority = None] [mutable = true] [canonical = true]
// Canonical + No authority allowed to update Metadata
// -> [authority = None] [mutable = false] [canonical = true]

// NEVER REACHED:
// -> [authority = Some(x)] [mutable = false] [canonical = true]
// Cleaned by the program.

// Third-party + Only authority x allowed to update Metadata
// -> [authority = Some(x)] [mutable = true] [canonical = false]
// Third-party + No authority allowed to update Metadata
// -> [authority = Some(x)] [mutable = false] [canonical = false]

// NEVER REACHED:
// -> [authority = None] [mutable = _] [canonical = true]
// Third-party should always have the seed authority set.

#[repr(C)]
#[derive(Clone, BorshSerialize, BorshDeserialize, Debug, ShankAccount)]
pub struct Counter {
pub key: Key,
pub authority: Pubkey,
pub value: u32,
pub struct Metadata {
pub discriminator: AccountDiscriminator,
pub program: Pubkey,
pub authority: Option<Pubkey>, // ZeroableOption.
mutable: u8, // get => is_mutable: bool
canonical: u8, // get => is_canonical: bool
pub seed: [u8; 17], // 16 + 1
pub encoding: Encoding,
pub compression: Compression,
pub format: Format,
pub data_source: DataSource,
// Trailing data.
}

impl Counter {
pub const LEN: usize = 1 + 32 + 4;
// (A: Canonical PDA) signer === program_authority => [program, seed ("idl")]
// -> create: signer === program_authority (data.mutable_authority = false)
// -> update: signer === program_authority || signer === metadata.authority
// -> close: signer === program_authority || signer === metadata.authority
// -> set_authority: signer === program_authority || signer === metadata.authority

// (B: Third-party PDA) signer === anyone => [program, authority, seed ("idl")]
// -> create: signer === anyone
// -> update: signer === metadata.authority
// -> close: signer === metadata.authority
// -> set_authority: NOT ALLOWED

impl Metadata {
pub const HEADER: usize = 1 + 32 + 32 + 19 + 1 + 1 + 1 + 1; // 88 bytes

pub fn seeds(authority: &Pubkey) -> Vec<&[u8]> {
vec!["counter".as_bytes(), authority.as_ref()]
pub fn seeds<'a>(program: &'a Pubkey, seed: &'a [u8; 16]) -> Vec<&'a [u8]> {
vec![program.as_ref(), seed.as_ref()]
}

pub fn find_pda(authority: &Pubkey) -> (Pubkey, u8) {
Pubkey::find_program_address(&Self::seeds(authority), &crate::ID)
pub fn find_pda<'a>(program: &'a Pubkey, seed: &'a [u8; 16]) -> (Pubkey, u8) {
Pubkey::find_program_address(&Self::seeds(program, seed), &crate::ID)
}

pub fn load(account: &AccountInfo) -> Result<Self, ProgramError> {
let mut bytes: &[u8] = &(*account.data).borrow();
Counter::deserialize(&mut bytes).map_err(|error| {
Metadata::deserialize(&mut bytes).map_err(|error| {
msg!("Error: {}", error);
CounterError::DeserializationError.into()
})
Expand All @@ -48,3 +82,52 @@ impl Counter {
})
}
}

#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)]
pub enum AccountDiscriminator {
Buffer,
Metadata,
}

#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)]
pub enum Encoding {
None,
Utf8,
Base58,
Base64,
}

#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)]
pub enum Compression {
None,
Gzip,
Zstd,
}

#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)]
pub enum Format {
None,
Json,
Yaml,
Toml,
}

#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)]
pub enum DataSource {
Direct,
Url,
External,
}

#[derive(Debug)]
pub struct DirectData<'a>(pub &'a [u8]);

#[derive(BorshSerialize, Debug)]
pub struct UrlData<'a>(pub &'a str);

#[derive(Clone, BorshSerialize, BorshDeserialize, Debug)]
pub struct ExternalData {
pub address: Pubkey,
pub offset: u32, // Default to 0.
pub length: Option<u32>, // ZeroableOption. 0 means the whole account.
}

0 comments on commit c908dd2

Please sign in to comment.