You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This discussion proposes a trait that can replace the generated entrypoint and dispatch code. Additional discussions will introduce traits for the rest of the anchor program lifecycle.
The AnchorProgram Trait
/// The main trait for anchor programs that gets automatically implemented by the `#[program]` macro./// This trait provides the program ID and error handling functionality.////// This takes inspiration from `star_frame`'s `StarFrameProgram` and `InstructionSet` traits.pubtraitAnchorProgram{/// Having the ID as an associated const on the program firstly enables the ID check in/// [`Self::entrypoint`], but will also enable other traits that have `AnchorProgram` associated/// types to access that ID. For example, if we had an AnchorAccount trait that belongs to an/// AnchorProgram (through an associated type), we could use this ID to check if the account is/// owned by the program. Among other things, this can also be useful when generating an IDL.////// This changes the way users declare their program IDs. Instead of using the `declare_id!` macro,/// they could either implement the trait manually or our macro could either require an ID constant/// declared in the program module or take it in with a derive helper attributeconstID:Pubkey;/// If the user wants to implement their own error handling logic, they can just override this method.fnhandle_error(err: anchor_lang::error::Error,) -> anchor_lang::solana_program::program_error::ProgramError{
err.log();
err.into()}/// By having this entrypoint as a default implementation, the entrypoint call can use this directly!/// ```rs/// #[cfg(not(feature = "no-entrypoint"))]/// anchor_lang::solana_program::entrypoint!(<MyProgram as AnchorProgram>::entrypoint);/// ```////// We also no longer have to generate the ID check!fnentrypoint<'info>(program_id:&Pubkey,accounts:&[AccountInfo<'info>],data:&[u8],) -> ProgramResult{if*program_id != Self::ID{returnErr(anchor_lang::error::ErrorCode::DeclaredProgramIdMismatch.into()).map_err(Self::handle_error);}Self::dispatch(program_id, accounts, data).map_err(Self::handle_error)}/// This method will be generated by the #[program] macro to figure out which instruction to call.fndispatch<'info>(program_id:&Pubkey,accounts:&[AccountInfo<'info>],data:&[u8],) -> Result<()>;}
Potential program module syntax and generated code
This would be how a basic program could be defined (the only change with current anchor is
that added ID const).
This could then expand to something like the following:
// If we want to keep the program module structure we can make this just be a unit struct that implements AnchorProgram,// but we could also accomplish all the macro shenanigans by making a user derive AnchorProgram on an enum of instructions.// That is currently what star_frame does (with some added indirection through a separate InstructionSet trait which I no longer// believe is necessary, hence the lack of one here)pubstructBasicProgram;implAnchorProgramforBasicProgram{constID:Pubkey = pubkey!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");fndispatch(program_id:&Pubkey,accounts:&[AccountInfo],data:&[u8]) -> Result<()>{if data.starts_with(instruction::Initialize::DISCRIMINATOR){// This should be different with a trait for instructions themselves as wellreturn __private::__global::initialize(
program_id,
accounts,&data[instruction::Initialize::DISCRIMINATOR.len()..],);}if data.starts_with(anchor_lang::event::EVENT_IX_TAG_LE){returnErr(anchor_lang::error::ErrorCode::EventInstructionStub.into());}Err(anchor_lang::error::ErrorCode::InstructionFallbackNotFound.into())}}pubmod instruction {usesuper::*;/// Instruction#[derive(AnchorSerialize,AnchorDeserialize)]pubstructInitialize{pubvalue:u8,}// An instruction trait that connects the instruction to it's Accounts would simplify a TON!// ---- currently auto-implemented anchor stuff below ----impl anchor_lang::DiscriminatorforInitialize{constDISCRIMINATOR:&'static[u8] = &[175,175,109,31,13,152,155,237];}impl anchor_lang::InstructionDataforInitialize{}impl anchor_lang::OwnerforInitialize{fnowner() -> Pubkey{ID}}}// No more entrypoint boilerplate! A user can directly follow the flow of their programs by just clicking through the default #[cfg(not(feature = "no-entrypoint"))]
anchor_lang::solana_program::entrypoint!(<BasicProgramasAnchorProgram>::entrypoint);// Plus the existing CPI stuff that already gets generated. A future issue will discuss some trait based alternatives!
Some questions:
From a macro perspective, forming that main dispatch method only requires knowing the instruction struct. Do we want to allow users to give their own structs to be included in the match (which would enable it to be included in the IDL as well if we generate that through a trait)?
Do we just replace the program macro with an enum of instructions altogether (or perhaps allow a user to do either or)?
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
(Duplicated from #4196)
This discussion proposes a trait that can replace the generated entrypoint and dispatch code. Additional discussions will introduce traits for the rest of the anchor program lifecycle.
The
AnchorProgramTraitPotential program module syntax and generated code
This would be how a basic program could be defined (the only change with current anchor is
that added ID const).
This could then expand to something like the following:
Some questions:
From a macro perspective, forming that main dispatch method only requires knowing the instruction struct. Do we want to allow users to give their own structs to be included in the match (which would enable it to be included in the IDL as well if we generate that through a trait)?
Do we just replace the program macro with an enum of instructions altogether (or perhaps allow a user to do either or)?
Beta Was this translation helpful? Give feedback.
All reactions