Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions program-error/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ edition = "2021"
[dependencies]
num-derive = "0.4"
num-traits = "0.2"
solana-program = "2.2.1"
solana-decode-error = "2.2.1"
solana-msg = "2.2.1"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually almost a leaf dependency. It depends on solana-define-syscall, which is a leaf.
So, this should work for all versions past 2.2.1 for 2.2 SDK crates. It's 2.3 where we'll see how it behaves, and if we do semver right in the SDK repo, we should be good!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hehe I did think about doing that -- we could even just redefine the syscall directly in this crate 😈

solana-program-error = "2.2.1"
spl-program-error-derive = { version = "0.4.1", path = "./derive" }
thiserror = "2.0"

[dev-dependencies]
lazy_static = "1.5"
serial_test = "3.2"
solana-sdk = "2.1.0"
solana-sha256-hasher = "2.2.1"
solana-sysvar = "2.2.1"

[lib]
crate-type = ["cdylib", "lib"]
Expand Down
32 changes: 16 additions & 16 deletions program-error/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

Macros for implementing error-based traits on enums.

- `#[derive(IntoProgramError)]`: automatically derives the trait `From<Self> for solana_program::program_error::ProgramError`.
- `#[derive(DecodeError)]`: automatically derives the trait `solana_program::decode_error::DecodeError<T>`.
- `#[derive(PrintProgramError)]`: automatically derives the trait `solana_program::program_error::PrintProgramError`.
- `#[derive(IntoProgramError)]`: automatically derives the trait `From<Self> for solana_program_error::ProgramError`.
- `#[derive(DecodeError)]`: automatically derives the trait `solana_decode_error::DecodeError<T>`.
- `#[derive(PrintProgramError)]`: automatically derives the trait `solana_program_error::PrintProgramError`.
- `#[spl_program_error]`: Automatically derives all below traits:
- `Clone`
- `Debug`
Expand All @@ -18,7 +18,7 @@ Macros for implementing error-based traits on enums.

### `#[derive(IntoProgramError)]`

This derive macro automatically derives the trait `From<Self> for solana_program::program_error::ProgramError`.
This derive macro automatically derives the trait `From<Self> for solana_program_error::ProgramError`.

Your enum must implement the following traits in order for this macro to work:

Expand Down Expand Up @@ -48,7 +48,7 @@ pub enum ExampleError {

### `#[derive(DecodeError)]`

This derive macro automatically derives the trait `solana_program::decode_error::DecodeError<T>`.
This derive macro automatically derives the trait `solana_decode_error::DecodeError<T>`.

Your enum must implement the following traits in order for this macro to work:

Expand Down Expand Up @@ -86,7 +86,7 @@ pub enum ExampleError {

### `#[derive(PrintProgramError)]`

This derive macro automatically derives the trait `solana_program::program_error::PrintProgramError`.
This derive macro automatically derives the trait `solana_program_error::PrintProgramError`.

Your enum must implement the following traits in order for this macro to work:

Expand Down Expand Up @@ -149,10 +149,10 @@ It also imports the required crates so you don't have to in your program:
Just annotate your enum...

```rust
use solana_program_error_derive::*;
use spl_program_error_derive::*;

/// Example error
#[solana_program_error]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha whoops. Thanks!

#[spl_program_error]
pub enum ExampleError {
/// Mint has no mint authority
#[error("Mint has no mint authority")]
Expand Down Expand Up @@ -261,29 +261,29 @@ impl ::core::cmp::PartialEq for ExampleError {
__self_tag == __arg1_tag
}
}
impl From<ExampleError> for solana_program::program_error::ProgramError {
impl From<ExampleError> for solana_program_error::ProgramError {
fn from(e: ExampleError) -> Self {
solana_program::program_error::ProgramError::Custom(e as u32)
solana_program_error::ProgramError::Custom(e as u32)
}
}
impl<T> solana_program::decode_error::DecodeError<T> for ExampleError {
impl<T> solana_decode_error::DecodeError<T> for ExampleError {
fn type_of() -> &'static str {
"ExampleError"
}
}
impl solana_program::program_error::PrintProgramError for ExampleError {
impl solana_program_error::PrintProgramError for ExampleError {
fn print<E>(&self)
where
E: 'static + std::error::Error + solana_program::decode_error::DecodeError<E>
+ solana_program::program_error::PrintProgramError
E: 'static + std::error::Error + solana_decode_error::DecodeError<E>
+ solana_program_error::PrintProgramError
+ num_traits::FromPrimitive,
{
match self {
ExampleError::MintHasNoMintAuthority => {
::solana_program::log::sol_log("Mint has no mint authority")
::solana_msg::sol_log("Mint has no mint authority")
}
ExampleError::IncorrectMintAuthority => {
::solana_program::log::sol_log(
::solana_msg::sol_log(
"Incorrect mint authority has signed the instruction",
)
}
Expand Down
12 changes: 6 additions & 6 deletions program-error/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use {
syn::{parse_macro_input, ItemEnum},
};

/// Derive macro to add `Into<solana_program::program_error::ProgramError>`
/// Derive macro to add `Into<solana_program_error::ProgramError>`
/// trait
#[proc_macro_derive(IntoProgramError)]
pub fn into_program_error(input: TokenStream) -> TokenStream {
Expand All @@ -33,14 +33,14 @@ pub fn into_program_error(input: TokenStream) -> TokenStream {
.into()
}

/// Derive macro to add `solana_program::decode_error::DecodeError` trait
/// Derive macro to add `solana_decode_error::DecodeError` trait
#[proc_macro_derive(DecodeError)]
pub fn decode_error(input: TokenStream) -> TokenStream {
let ItemEnum { ident, .. } = parse_macro_input!(input as ItemEnum);
MacroType::DecodeError { ident }.generate_tokens().into()
}

/// Derive macro to add `solana_program::program_error::PrintProgramError` trait
/// Derive macro to add `solana_program_error::PrintProgramError` trait
#[proc_macro_derive(PrintProgramError)]
pub fn print_program_error(input: TokenStream) -> TokenStream {
let ItemEnum {
Expand All @@ -60,9 +60,9 @@ pub fn print_program_error(input: TokenStream) -> TokenStream {
/// - `PartialEq`
/// - `thiserror::Error`
/// - `num_derive::FromPrimitive`
/// - `Into<solana_program::program_error::ProgramError>`
/// - `solana_program::decode_error::DecodeError`
/// - `solana_program::program_error::PrintProgramError`
/// - `Into<solana_program_error::ProgramError>`
/// - `solana_decode_error::DecodeError`
/// - `solana_program_error::PrintProgramError`
///
/// Optionally, you can add `hash_error_code_start: u32` argument to create
/// a unique `u32` _starting_ error codes from the names of the enum variants.
Expand Down
60 changes: 36 additions & 24 deletions program-error/derive/src/macro_impl.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! The actual token generator for the macro

use {
crate::parser::{SolanaProgram, SplProgramErrorArgs},
crate::parser::{SolanaDecodeError, SolanaProgramError, SplProgramErrorArgs},
proc_macro2::Span,
quote::quote,
sha2::{Digest, Sha256},
Expand Down Expand Up @@ -36,36 +36,42 @@ pub enum MacroType {
impl MacroType {
/// Generates the corresponding tokens based on variant selection
pub fn generate_tokens(&mut self) -> proc_macro2::TokenStream {
let default_solana_program = SolanaProgram::default();
let default_solana_program_error = SolanaProgramError::default();
let default_solana_decode_error = SolanaDecodeError::default();
match self {
Self::IntoProgramError { ident } => into_program_error(ident, &default_solana_program),
Self::DecodeError { ident } => decode_error(ident, &default_solana_program),
Self::PrintProgramError { ident, variants } => {
print_program_error(ident, variants, &default_solana_program)
Self::IntoProgramError { ident } => {
into_program_error(ident, &default_solana_program_error)
}
Self::DecodeError { ident } => decode_error(ident, &default_solana_decode_error),
Self::PrintProgramError { ident, variants } => print_program_error(
ident,
variants,
&default_solana_program_error,
&default_solana_decode_error,
),
Self::SplProgramError { args, item_enum } => spl_program_error(args, item_enum),
}
}
}

/// Builds the implementation of
/// `Into<solana_program::program_error::ProgramError>` More specifically,
/// implements `From<Self> for solana_program::program_error::ProgramError`
pub fn into_program_error(ident: &Ident, import: &SolanaProgram) -> proc_macro2::TokenStream {
/// `Into<solana_program_error::ProgramError>` More specifically,
/// implements `From<Self> for solana_program_error::ProgramError`
pub fn into_program_error(ident: &Ident, import: &SolanaProgramError) -> proc_macro2::TokenStream {
let this_impl = quote! {
impl From<#ident> for #import::program_error::ProgramError {
impl From<#ident> for #import::ProgramError {
fn from(e: #ident) -> Self {
#import::program_error::ProgramError::Custom(e as u32)
#import::ProgramError::Custom(e as u32)
}
}
};
import.wrap(this_impl)
}

/// Builds the implementation of `solana_program::decode_error::DecodeError<T>`
pub fn decode_error(ident: &Ident, import: &SolanaProgram) -> proc_macro2::TokenStream {
/// Builds the implementation of `solana_decode_error::DecodeError<T>`
pub fn decode_error(ident: &Ident, import: &SolanaDecodeError) -> proc_macro2::TokenStream {
let this_impl = quote! {
impl<T> #import::decode_error::DecodeError<T> for #ident {
impl<T> #import::DecodeError<T> for #ident {
fn type_of() -> &'static str {
stringify!(#ident)
}
Expand All @@ -75,30 +81,31 @@ pub fn decode_error(ident: &Ident, import: &SolanaProgram) -> proc_macro2::Token
}

/// Builds the implementation of
/// `solana_program::program_error::PrintProgramError`
/// `solana_program_error::PrintProgramError`
pub fn print_program_error(
ident: &Ident,
variants: &Punctuated<Variant, Comma>,
import: &SolanaProgram,
program_error_import: &SolanaProgramError,
decode_error_import: &SolanaDecodeError,
) -> proc_macro2::TokenStream {
let ppe_match_arms = variants.iter().map(|variant| {
let variant_ident = &variant.ident;
let error_msg = get_error_message(variant)
.unwrap_or_else(|| String::from("Unknown custom program error"));
quote! {
#ident::#variant_ident => {
#import::msg!(#error_msg)
::solana_msg::msg!(#error_msg)
}
}
});
let this_impl = quote! {
impl #import::program_error::PrintProgramError for #ident {
impl #program_error_import::PrintProgramError for #ident {
fn print<E>(&self)
where
E: 'static
+ std::error::Error
+ #import::decode_error::DecodeError<E>
+ #import::program_error::PrintProgramError
+ #decode_error_import::DecodeError<E>
+ #program_error_import::PrintProgramError
+ num_traits::FromPrimitive,
{
match self {
Expand All @@ -107,7 +114,7 @@ pub fn print_program_error(
}
}
};
import.wrap(this_impl)
program_error_import.wrap(decode_error_import.wrap(this_impl))
}

/// Helper to parse out the string literal from the `#[error(..)]` attribute
Expand Down Expand Up @@ -135,9 +142,14 @@ pub fn spl_program_error(

let ident = &item_enum.ident;
let variants = &item_enum.variants;
let into_program_error = into_program_error(ident, &args.import);
let decode_error = decode_error(ident, &args.import);
let print_program_error = print_program_error(ident, variants, &args.import);
let into_program_error = into_program_error(ident, &args.program_error_import);
let decode_error = decode_error(ident, &args.decode_error_import);
let print_program_error = print_program_error(
ident,
variants,
&args.program_error_import,
&args.decode_error_import,
);

quote! {
#[repr(u32)]
Expand Down
Loading
Loading