Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make ProgramError compatible with pinocchio #12

Open
wants to merge 17 commits into
base: master
Choose a base branch
from

Conversation

kevinheavey
Copy link
Contributor

Problem: solana-program-error and pinocchio define ProgramError enums that are identical except for the BorshIoError variant, which looks like BorshIoError(String) in solana-program-error and is fieldless (just BorshIoError) in pinocchio.

It is going to be a significant source of grief for users to have two almost-identical ProgramError types in their dependency tree. People will accidentally import the wrong one a lot

Solution: make solana_program_error::ProgramError the same as the pinocchio one so pinocchio can replace its definition with a re-export.

Breaking changes:

  • the BorshIoError variants of ProgramError and InstructionError become fieldless. This will require a major version bump for solana-program-error, solana-instruction-error, solana-program and solana-sdk. I haven't included the version bump in the PR as it breaks compilation because of the solana-system-interface dep. This may or may not be curable with patching but is ultimately not a real problem.
  • add a num-traits feature to solana-program-error so that all functionality requiring num-traits becomes optional (pinocchio isn't using this functionality)
  • make std optional in solana-program-error as pinocchio is no-std. The only thing this affects is impl std::error::Error for ProgramError {}

Other changes:

  • Extract solana-pubkey-error and solana-instruction-error crates and use them in solana-program-error. This is so pinocchio's deps can be as light as possible
  • Make num-traits optional

@kevinheavey
Copy link
Contributor Author

CI error is as expected given the breaking change

@kevinheavey kevinheavey force-pushed the program-error-pinocchio-compat branch from f625acf to bc3494a Compare February 13, 2025 09:16
solana-msg = { workspace = true }
solana-pubkey = { workspace = true, default-features = false }
solana-decode-error = { workspace = true, optional = true }
solana-instruction-error = { workspace = true }
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make this one optional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

are you sure? I think this is at the point where the cognitive overhead of the extra feature outweighs any impact on compile times or API surface area

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, the amount of features to enable/disable depending of whether you are using pinocchio or the SDK concerns me - hopefully is not going to be annoying.

Ideally I would not have solana-instruction-error and solana-pubkey-error exported here – those should be added by the code that wants to use them. So the other option is to remove the export from here, instead of adding another feature.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

pinocchio would want the error codes defined in solana-instruction-error e.g. pub const INVALID_ARGUMENT: u64 = to_builtin!(2);. Currently it's redefining these itself. Are you saying you'd want these consts to be in a standalone crate without the InstructionError enum?

Copy link
Contributor

Choose a reason for hiding this comment

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

I was thinking that we can have the error codes defined in solana-program-error, like in pinocchio. So solana-instruction-error is the one that depends on solana-program-error, not the other way around. The error codes cover the "program errors" variants and InstructionError is a super set of ProgramError.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok i've moved some stuff to program-error

solana-decode-error = { workspace = true, optional = true }
solana-instruction-error = { workspace = true }
solana-msg = { workspace = true, optional = true }
solana-pubkey-error = { workspace = true, default-features = false }
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make this one optional?

solana_decode_error::DecodeError,
solana_instruction::error::{
core::{convert::TryFrom, fmt},
solana_instruction_error::{
Copy link
Contributor

Choose a reason for hiding this comment

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

If we make solana-instruction-error optional, we should add a feature here.

solana_msg::msg,
solana_pubkey::PubkeyError,
std::convert::TryFrom,
solana_pubkey_error::PubkeyError,
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here, If we make solana-pubkey-error optional, we should add a feature here.

@@ -122,12 +124,14 @@ impl fmt::Display for ProgramError {
}
}

#[cfg(feature = "num-traits")]
pub trait PrintProgramError {
fn print<E>(&self)
where
E: 'static + std::error::Error + DecodeError<E> + PrintProgramError + FromPrimitive;
Copy link
Contributor

@febo febo Feb 13, 2025

Choose a reason for hiding this comment

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

Is there a way to relax the requirements for E? E.g., drop std::error::Error and FromPrimitive. This way we could use the trait in pinocchio-based errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can remove the DecodeError and Error constraints, which is technically a breaking change but is trivial and we're already making a breaking change here, so I've committed that.

We can replace the FromPrimitive constraint with TryFrom but this is a more significant break because users would have to write their own impl or switch to num_enum to derive it https://docs.rs/num_enum/latest/num_enum/derive.TryFromPrimitive.html. For now I've committed this change too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants