Skip to content

Commit 4c3fabd

Browse files
authored
p-token: Fix error codes (solana-program#52)
* Fix error codes * Fix formatting * Add validation on load * Fix formatting * Fix typo * Relax instruction data length check * Another relax length check * More relax instruction data length check * Move account validation * Fix rent exempt check * Update pinocchio reference * Improve coption validation * Streamline initialize check * Add unpack helpers
1 parent 001b6a2 commit 4c3fabd

37 files changed

+229
-198
lines changed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

interface/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ readme = "./README.md"
1212
crate-type = ["rlib"]
1313

1414
[dependencies]
15-
pinocchio = "0.8"
16-
pinocchio-pubkey = "0.2.4"
15+
pinocchio = "0.8.4"
16+
pinocchio-pubkey = "0.2"
1717

1818
[dev-dependencies]
1919
strum = "0.27"

interface/src/instruction.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Instruction types.
22
3-
use pinocchio::program_error::ProgramError;
3+
use {crate::error::TokenError, pinocchio::program_error::ProgramError};
44

55
/// Instructions supported by the token program.
66
#[repr(u8)]
@@ -531,7 +531,7 @@ impl TryFrom<u8> for TokenInstruction {
531531
match value {
532532
// SAFETY: `value` is guaranteed to be in the range of the enum variants.
533533
0..=24 | 38 | 255 => Ok(unsafe { core::mem::transmute::<u8, TokenInstruction>(value) }),
534-
_ => Err(ProgramError::InvalidInstructionData),
534+
_ => Err(TokenError::InvalidInstruction.into()),
535535
}
536536
}
537537
}
@@ -559,7 +559,7 @@ impl TryFrom<u8> for AuthorityType {
559559
match value {
560560
// SAFETY: `value` is guaranteed to be in the range of the enum variants.
561561
0..=3 => Ok(unsafe { core::mem::transmute::<u8, AuthorityType>(value) }),
562-
_ => Err(ProgramError::InvalidInstructionData),
562+
_ => Err(TokenError::InvalidInstruction.into()),
563563
}
564564
}
565565
}

interface/src/state/account.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use {
22
super::{account_state::AccountState, COption, Initializable, Transmutable},
3-
pinocchio::pubkey::Pubkey,
3+
pinocchio::{program_error::ProgramError, pubkey::Pubkey},
44
};
55

66
/// Incinerator address.
@@ -27,7 +27,7 @@ pub struct Account {
2727
delegate: COption<Pubkey>,
2828

2929
/// The account's state.
30-
pub state: AccountState,
30+
state: u8,
3131

3232
/// Indicates whether this account represents a native token or not.
3333
is_native: [u8; 4],
@@ -46,6 +46,16 @@ pub struct Account {
4646
}
4747

4848
impl Account {
49+
#[inline(always)]
50+
pub fn set_account_state(&mut self, state: AccountState) {
51+
self.state = state as u8;
52+
}
53+
54+
#[inline(always)]
55+
pub fn account_state(&self) -> Result<AccountState, ProgramError> {
56+
AccountState::try_from(self.state)
57+
}
58+
4959
#[inline(always)]
5060
pub fn set_amount(&mut self, amount: u64) {
5161
self.amount = amount.to_le_bytes();
@@ -131,8 +141,8 @@ impl Account {
131141
}
132142

133143
#[inline(always)]
134-
pub fn is_frozen(&self) -> bool {
135-
self.state == AccountState::Frozen
144+
pub fn is_frozen(&self) -> Result<bool, ProgramError> {
145+
AccountState::try_from(self.state).map(|state| state == AccountState::Frozen)
136146
}
137147

138148
#[inline(always)]
@@ -147,7 +157,7 @@ impl Transmutable for Account {
147157

148158
impl Initializable for Account {
149159
#[inline(always)]
150-
fn is_initialized(&self) -> bool {
151-
self.state != AccountState::Uninitialized
160+
fn is_initialized(&self) -> Result<bool, ProgramError> {
161+
AccountState::try_from(self.state).map(|state| state != AccountState::Uninitialized)
152162
}
153163
}

interface/src/state/account_state.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use pinocchio::program_error::ProgramError;
2+
13
#[repr(u8)]
24
#[derive(Clone, Copy, Debug, PartialEq)]
35
pub enum AccountState {
@@ -13,3 +15,16 @@ pub enum AccountState {
1315
/// this account.
1416
Frozen,
1517
}
18+
19+
impl TryFrom<u8> for AccountState {
20+
type Error = ProgramError;
21+
22+
#[inline(always)]
23+
fn try_from(value: u8) -> Result<Self, Self::Error> {
24+
match value {
25+
// SAFETY: `value` is guaranteed to be in the range of the enum variants.
26+
0..=2 => Ok(unsafe { core::mem::transmute::<u8, AccountState>(value) }),
27+
_ => Err(ProgramError::InvalidAccountData),
28+
}
29+
}
30+
}

interface/src/state/mint.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use {
22
super::{COption, Initializable, Transmutable},
3-
pinocchio::pubkey::Pubkey,
3+
pinocchio::{program_error::ProgramError, pubkey::Pubkey},
44
};
55

66
/// Internal representation of a mint data.
@@ -10,7 +10,7 @@ pub struct Mint {
1010
/// be provided during mint creation. If no mint authority is present
1111
/// then the mint has a fixed supply and no further tokens may be
1212
/// minted.
13-
pub mint_authority: COption<Pubkey>,
13+
mint_authority: COption<Pubkey>,
1414

1515
/// Total supply of tokens.
1616
supply: [u8; 8],
@@ -24,7 +24,7 @@ pub struct Mint {
2424
// Indicates whether the freeze authority is present or not.
2525
//freeze_authority_option: [u8; 4],
2626
/// Optional authority to freeze token accounts.
27-
pub freeze_authority: COption<Pubkey>,
27+
freeze_authority: COption<Pubkey>,
2828
}
2929

3030
impl Mint {
@@ -91,7 +91,11 @@ impl Transmutable for Mint {
9191

9292
impl Initializable for Mint {
9393
#[inline(always)]
94-
fn is_initialized(&self) -> bool {
95-
self.is_initialized == 1
94+
fn is_initialized(&self) -> Result<bool, ProgramError> {
95+
match self.is_initialized {
96+
0 => Ok(false),
97+
1 => Ok(true),
98+
_ => Err(ProgramError::InvalidAccountData),
99+
}
96100
}
97101
}

interface/src/state/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub trait Transmutable {
2323
/// Trait to represent a type that can be initialized.
2424
pub trait Initializable {
2525
/// Return `true` if the object is initialized.
26-
fn is_initialized(&self) -> bool;
26+
fn is_initialized(&self) -> Result<bool, ProgramError>;
2727
}
2828

2929
/// Return a reference for an initialized `T` from the given bytes.
@@ -35,7 +35,7 @@ pub trait Initializable {
3535
pub unsafe fn load<T: Initializable + Transmutable>(bytes: &[u8]) -> Result<&T, ProgramError> {
3636
load_unchecked(bytes).and_then(|t: &T| {
3737
// checks if the data is initialized
38-
if t.is_initialized() {
38+
if t.is_initialized()? {
3939
Ok(t)
4040
} else {
4141
Err(ProgramError::UninitializedAccount)
@@ -69,7 +69,7 @@ pub unsafe fn load_mut<T: Initializable + Transmutable>(
6969
) -> Result<&mut T, ProgramError> {
7070
load_mut_unchecked(bytes).and_then(|t: &mut T| {
7171
// checks if the data is initialized
72-
if t.is_initialized() {
72+
if t.is_initialized()? {
7373
Ok(t)
7474
} else {
7575
Err(ProgramError::UninitializedAccount)

interface/src/state/multisig.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use {
22
super::{Initializable, Transmutable},
3-
pinocchio::pubkey::Pubkey,
3+
pinocchio::{program_error::ProgramError, pubkey::Pubkey},
44
};
55

66
/// Minimum number of multisignature signers (min N)
@@ -18,10 +18,10 @@ pub struct Multisig {
1818
/// Number of valid signers.
1919
pub n: u8,
2020

21-
/// Is `true` if this structure has been initialized
21+
/// Is `true` if this structure has been initialized.
2222
is_initialized: u8,
2323

24-
/// Signer public keys
24+
/// Signer public keys.
2525
pub signers: [Pubkey; MAX_SIGNERS as usize],
2626
}
2727

@@ -39,13 +39,17 @@ impl Multisig {
3939
}
4040

4141
impl Transmutable for Multisig {
42-
/// The length of the `Mint` account data.
42+
/// The length of the `Multisig` account data.
4343
const LEN: usize = core::mem::size_of::<Multisig>();
4444
}
4545

4646
impl Initializable for Multisig {
4747
#[inline(always)]
48-
fn is_initialized(&self) -> bool {
49-
self.is_initialized == 1
48+
fn is_initialized(&self) -> Result<bool, ProgramError> {
49+
match self.is_initialized {
50+
0 => Ok(false),
51+
1 => Ok(true),
52+
_ => Err(ProgramError::InvalidAccountData),
53+
}
5054
}
5155
}

p-token/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ crate-type = ["cdylib"]
1515
logging = []
1616

1717
[dependencies]
18-
pinocchio = "0.8"
18+
pinocchio = "0.8.4"
1919
pinocchio-log = { version = "0.4", default-features = false }
2020
spl-token-interface = { version = "^0", path = "../interface" }
2121

p-token/src/entrypoint.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub fn process_instruction(
3636
instruction_data: &[u8],
3737
) -> ProgramResult {
3838
let [discriminator, remaining @ ..] = instruction_data else {
39-
return Err(ProgramError::InvalidInstructionData);
39+
return Err(TokenError::InvalidInstruction.into());
4040
};
4141

4242
let result = if *discriminator == 255 {
@@ -78,7 +78,7 @@ pub(crate) fn inner_process_instruction(
7878
instruction_data: &[u8],
7979
) -> ProgramResult {
8080
let [discriminator, instruction_data @ ..] = instruction_data else {
81-
return Err(ProgramError::InvalidInstructionData);
81+
return Err(TokenError::InvalidInstruction.into());
8282
};
8383

8484
match *discriminator {
@@ -194,7 +194,7 @@ fn inner_process_remaining_instruction(
194194
#[cfg(feature = "logging")]
195195
pinocchio::msg!("Instruction: Revoke");
196196

197-
process_revoke(accounts, instruction_data)
197+
process_revoke(accounts)
198198
}
199199
// 6 - SetAuthority
200200
6 => {
@@ -280,6 +280,6 @@ fn inner_process_remaining_instruction(
280280

281281
process_withdraw_excess_lamports(accounts)
282282
}
283-
_ => Err(ProgramError::InvalidInstructionData),
283+
_ => Err(TokenError::InvalidInstruction.into()),
284284
}
285285
}

0 commit comments

Comments
 (0)