diff --git a/programs/bpf/c/src/error_handling/error_handling.c b/programs/bpf/c/src/error_handling/error_handling.c index 5fc293123a..c046c9a320 100644 --- a/programs/bpf/c/src/error_handling/error_handling.c +++ b/programs/bpf/c/src/error_handling/error_handling.c @@ -35,6 +35,9 @@ extern uint64_t entrypoint(const uint8_t *input) { case(6): sol_log("return unknown builtin"); return TO_BUILTIN(50); + case(9): + sol_log("return pubkey error"); + return MAX_SEED_LENGTH_EXCEEDED; default: sol_log("Unrecognized command"); return ERROR_INVALID_INSTRUCTION_DATA; diff --git a/programs/bpf/rust/error_handling/src/lib.rs b/programs/bpf/rust/error_handling/src/lib.rs index 37c2df5017..25d792ade3 100644 --- a/programs/bpf/rust/error_handling/src/lib.rs +++ b/programs/bpf/rust/error_handling/src/lib.rs @@ -10,7 +10,7 @@ use solana_sdk::{ entrypoint::ProgramResult, info, program_error::{PrintProgramError, ProgramError}, - pubkey::Pubkey, + pubkey::{Pubkey, PubkeyError}, }; use thiserror::Error; @@ -73,6 +73,10 @@ fn process_instruction( assert_eq!(*data, *data2); Ok(()) } + 9 => { + info!("return pubkey error"); + Err(PubkeyError::MaxSeedLengthExceeded.into()) + } _ => { info!("Unsupported"); Err(ProgramError::InvalidInstructionData) diff --git a/programs/bpf/tests/programs.rs b/programs/bpf/tests/programs.rs index b29d0cfd00..b36023ed25 100644 --- a/programs/bpf/tests/programs.rs +++ b/programs/bpf/tests/programs.rs @@ -301,6 +301,14 @@ mod bpf { result.unwrap_err().unwrap(), TransactionError::InstructionError(0, InstructionError::InvalidInstructionData) ); + + let instruction = Instruction::new(program_id, &9u8, account_metas.clone()); + let result = bank_client.send_instruction(&mint_keypair, instruction); + assert_eq!( + result.unwrap_err().unwrap(), + TransactionError::InstructionError(0, InstructionError::MaxSeedLengthExceeded) + ); + } } diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index 9813b16e80..9615fcabee 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -109,6 +109,8 @@ static_assert(sizeof(uint64_t) == 8); #define ERROR_NOT_ENOUGH_ACCOUNT_KEYS TO_BUILTIN(11) /** Note: Not applicable to program written in C */ #define ERROR_ACCOUNT_BORROW_FAILED TO_BUILTIN(12) +/** The length of the seed is too long for address generation */ +#define MAX_SEED_LENGTH_EXCEEDED TO_BUILTIN(13) /** * Boolean type @@ -129,7 +131,6 @@ void sol_log_(const char *, uint64_t); void sol_log_64_(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); #define sol_log_64 sol_log_64_ - /** * Size of Public key in bytes */ diff --git a/sdk/src/instruction.rs b/sdk/src/instruction.rs index a6b13b4981..6131c37355 100644 --- a/sdk/src/instruction.rs +++ b/sdk/src/instruction.rs @@ -151,6 +151,10 @@ pub enum InstructionError { /// Cross-program invocation reentrancy not allowed for this instruction #[error("Cross-program invocation reentrancy not allowed for this instruction")] ReentrancyNotAllowed, + + /// Length of the seed is too long for address generation + #[error("Length of the seed is too long for address generation")] + MaxSeedLengthExceeded, } impl InstructionError { diff --git a/sdk/src/program_error.rs b/sdk/src/program_error.rs index 91dac2993f..a308291dd5 100644 --- a/sdk/src/program_error.rs +++ b/sdk/src/program_error.rs @@ -1,4 +1,4 @@ -use crate::{decode_error::DecodeError, instruction::InstructionError}; +use crate::{decode_error::DecodeError, instruction::InstructionError, pubkey::PubkeyError}; use num_traits::{FromPrimitive, ToPrimitive}; use std::convert::TryFrom; use thiserror::Error; @@ -38,6 +38,8 @@ pub enum ProgramError { NotEnoughAccountKeys, #[error("Failed to borrow a reference to account data, already borrowed")] AccountBorrowFailed, + #[error("Length of the seed is too long for address generation")] + MaxSeedLengthExceeded, } pub trait PrintProgramError { @@ -70,6 +72,7 @@ impl PrintProgramError for ProgramError { Self::UninitializedAccount => info!("Error: UninitializedAccount"), Self::NotEnoughAccountKeys => info!("Error: NotEnoughAccountKeys"), Self::AccountBorrowFailed => info!("Error: AccountBorrowFailed"), + Self::MaxSeedLengthExceeded => info!("Error: MaxSeedLengthExceeded"), } } } @@ -94,6 +97,7 @@ const ACCOUNT_ALREADY_INITIALIZED: u64 = to_builtin!(9); const UNINITIALIZED_ACCOUNT: u64 = to_builtin!(10); const NOT_ENOUGH_ACCOUNT_KEYS: u64 = to_builtin!(11); const ACCOUNT_BORROW_FAILED: u64 = to_builtin!(12); +const MAX_SEED_LENGTH_EXCEEDED: u64 = to_builtin!(13); impl From for u64 { fn from(error: ProgramError) -> Self { @@ -109,6 +113,7 @@ impl From for u64 { ProgramError::UninitializedAccount => UNINITIALIZED_ACCOUNT, ProgramError::NotEnoughAccountKeys => NOT_ENOUGH_ACCOUNT_KEYS, ProgramError::AccountBorrowFailed => ACCOUNT_BORROW_FAILED, + ProgramError::MaxSeedLengthExceeded => MAX_SEED_LENGTH_EXCEEDED, ProgramError::Custom(error) => { if error == 0 { CUSTOM_ZERO @@ -134,6 +139,7 @@ impl From for ProgramError { UNINITIALIZED_ACCOUNT => ProgramError::UninitializedAccount, NOT_ENOUGH_ACCOUNT_KEYS => ProgramError::NotEnoughAccountKeys, ACCOUNT_BORROW_FAILED => ProgramError::AccountBorrowFailed, + MAX_SEED_LENGTH_EXCEEDED => ProgramError::MaxSeedLengthExceeded, CUSTOM_ZERO => ProgramError::Custom(0), _ => ProgramError::Custom(error as u32), } @@ -157,6 +163,7 @@ impl TryFrom for ProgramError { Self::Error::UninitializedAccount => Ok(Self::UninitializedAccount), Self::Error::NotEnoughAccountKeys => Ok(Self::NotEnoughAccountKeys), Self::Error::AccountBorrowFailed => Ok(Self::AccountBorrowFailed), + Self::Error::MaxSeedLengthExceeded => Ok(Self::MaxSeedLengthExceeded), _ => Err(error), } } @@ -181,6 +188,7 @@ where UNINITIALIZED_ACCOUNT => InstructionError::UninitializedAccount, NOT_ENOUGH_ACCOUNT_KEYS => InstructionError::NotEnoughAccountKeys, ACCOUNT_BORROW_FAILED => InstructionError::AccountBorrowFailed, + MAX_SEED_LENGTH_EXCEEDED => InstructionError::MaxSeedLengthExceeded, _ => { // A valid custom error has no bits set in the upper 32 if error >> BUILTIN_BIT_SHIFT == 0 { @@ -192,3 +200,11 @@ where } } } + +impl From for ProgramError { + fn from(error: PubkeyError) -> Self { + match error { + PubkeyError::MaxSeedLengthExceeded => ProgramError::MaxSeedLengthExceeded, + } + } +} diff --git a/sdk/src/pubkey.rs b/sdk/src/pubkey.rs index 80bf7e6da5..a41b9b1801 100644 --- a/sdk/src/pubkey.rs +++ b/sdk/src/pubkey.rs @@ -15,7 +15,8 @@ pub const MAX_SEED_LEN: usize = 32; #[derive(Error, Debug, Serialize, Clone, PartialEq, FromPrimitive, ToPrimitive)] pub enum PubkeyError { - #[error("length of requested seed is too long")] + /// Length of the seed is too long for address generation + #[error("Length of the seed is too long for address generation")] MaxSeedLengthExceeded, } impl DecodeError for PubkeyError {