From c908dd20cf14b3684aee95e393f4e653744ea8b5 Mon Sep 17 00:00:00 2001 From: Loris Leiva Date: Tue, 7 Jan 2025 15:47:19 +0100 Subject: [PATCH] Add prototyping comments --- program/src/assertions.rs | 8 ++- program/src/instruction.rs | 6 ++ program/src/processor/create.rs | 12 ++-- program/src/state.rs | 115 +++++++++++++++++++++++++++----- 4 files changed, 117 insertions(+), 24 deletions(-) diff --git a/program/src/assertions.rs b/program/src/assertions.rs index 0027d01..d30fcf3 100644 --- a/program/src/assertions.rs +++ b/program/src/assertions.rs @@ -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, @@ -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!( diff --git a/program/src/instruction.rs b/program/src/instruction.rs index 7dce207..1cbeeb2 100644 --- a/program/src/instruction.rs +++ b/program/src/instruction.rs @@ -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 } diff --git a/program/src/processor/create.rs b/program/src/processor/create.rs index a0f54db..5df0ae6 100644 --- a/program/src/processor/create.rs +++ b/program/src/processor/create.rs @@ -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}; @@ -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)?; @@ -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]), )?; diff --git a/program/src/state.rs b/program/src/state.rs index 7ea8ac4..741c136 100644 --- a/program/src/state.rs +++ b/program/src/state.rs @@ -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, // 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 { 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() }) @@ -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, // ZeroableOption. 0 means the whole account. +}