-
Notifications
You must be signed in to change notification settings - Fork 164
feat: middleware entrypoint #241
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
Open
deanmlittle
wants to merge
6
commits into
anza-xyz:main
Choose a base branch
from
deanmlittle:feature/middleware-entrypoint
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 5 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
e5f42d0
feat: middleware entrypoint
deanmlittle fa62057
Update sdk/pinocchio/src/entrypoint/middleware.rs
deanmlittle 60379aa
Update sdk/pinocchio/src/entrypoint/middleware.rs
deanmlittle 57a94b0
Update sdk/pinocchio/src/entrypoint/middleware.rs
deanmlittle d3d3c95
documentation and typo fixes
deanmlittle d07ad3b
Added feature for assembly-level entrypoint optimizations
deanmlittle File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -172,6 +172,48 @@ pub fn process_instruction( | |||||
| > ⚠️ **Note:** | ||||||
| > The `no_allocator!` macro can also be used in combination with the `lazy_program_entrypoint!`. | ||||||
|
|
||||||
| 📌 [`middleware_program_entrypoint!`](https://docs.rs/pinocchio/latest/pinocchio/macro.middleware_program_entrypoint.html) | ||||||
|
|
||||||
| The `middleware_program_entrypoint!` macro defines a dual entrypoint implementation consisting of a `hot` path which bypasses entrypoint deserialization, and a `cold` path with behaves like a regular pinocchio entrypoint that has undergone `program_entrypoint!` deserialization. This gives the user flexibility to implement extreme CU optimizations against the most critical paths in their proggram with the convenience of being able to fallback to a regular pinocchio program to manage the fail case and other instructions that do not require such optimizations. | ||||||
|
|
||||||
| To use the `middleware_program_entrypoint!` macro, use the following in your entrypoint definition: | ||||||
|
|
||||||
| ```rust | ||||||
| #![cfg_attr(target_os = "solana", no_std)] | ||||||
| use pinocchio::{ | ||||||
| ProgramResult, | ||||||
| account_info::AccountInfo, | ||||||
| middleware_program_entrypoint, | ||||||
| msg, | ||||||
| no_allocator, | ||||||
| nostd_panic_handler, | ||||||
| pubkey::Pubkey | ||||||
| }; | ||||||
|
|
||||||
| nostd_panic_handler!(); | ||||||
| no_allocator!(); | ||||||
|
|
||||||
| middleware_program_entrypoint!(hot,cold); | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| // This uses 4 CUs | ||||||
| #[inline(always)] | ||||||
| pub fn hot(input: *mut u8) -> u64 { | ||||||
| unsafe { *input as u64 } | ||||||
| } | ||||||
|
|
||||||
| // This uses 113 CUs | ||||||
| #[cold] | ||||||
| #[inline(always)] | ||||||
| pub fn cold( | ||||||
| _program_id: &Pubkey, | ||||||
| _accounts: &[AccountInfo], | ||||||
| _instruction_data: &[u8], | ||||||
| ) -> ProgramResult { | ||||||
| msg!("Hello from Pinocchio!"); | ||||||
| Ok(()) | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| ## Crate feature: `std` | ||||||
|
|
||||||
| By default, `pinocchio` is a `no_std` crate. This means that it does not use any code from the standard (`std`) library. While this does not affect how `pinocchio` is used, there is one particular apparent difference. In a `no_std` environment, the `msg!` macro does not provide any formatting options since the `format!` macro requires the `std` library. In order to use `msg!` with formatting, the `std` feature should be enabled when adding `pinocchio` as a dependency: | ||||||
|
|
||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,94 @@ | ||||||||
| //! Defines the middleware program entrypoint, enabling a hot path to bypass | ||||||||
| //! entrypoint deserialization, ejecting to the cold path on failure. | ||||||||
deanmlittle marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||
| /// Declare the middleware program entrypoint. | ||||||||
| /// | ||||||||
| /// The macro expects a `hot` and `cold` path expressions. The `hot` is a function with | ||||||||
| /// the following type signature: | ||||||||
| /// | ||||||||
| /// ```ignore | ||||||||
| /// fn hot(input: mut *u8) -> u64; | ||||||||
| /// ``` | ||||||||
| /// The `input` argument represents the program input parameters serialized by the SVM | ||||||||
| /// loader. The `cold` is a function with the following type signature: | ||||||||
| /// | ||||||||
| /// ```ignore | ||||||||
| /// fn cold( | ||||||||
| /// program_id: &Pubkey, // Public key of the account the program was loaded into | ||||||||
| /// accounts: &[AccountInfo], // All accounts required to process the instruction | ||||||||
| /// instruction_data: &[u8], // Serialized instruction-specific data | ||||||||
| /// ) -> ProgramResult; | ||||||||
| /// ``` | ||||||||
| /// # Example | ||||||||
| /// | ||||||||
| /// A middleware program entrypoint where an invocation with zero accounts will lead to | ||||||||
| /// the "hot" path, and anything else will fallback to the "cold" path: | ||||||||
| /// | ||||||||
| /// ```norun | ||||||||
| /// #![cfg_attr(target_os = "solana", no_std)] | ||||||||
| /// use pinocchio::{ | ||||||||
| /// ProgramResult, | ||||||||
| /// account_info::AccountInfo, | ||||||||
| /// middleware_program_entrypoint, | ||||||||
| /// msg, | ||||||||
| /// no_allocator, | ||||||||
| /// nostd_panic_handler, | ||||||||
| /// pubkey::Pubkey | ||||||||
| /// }; | ||||||||
| /// | ||||||||
| /// nostd_panic_handler!(); | ||||||||
| /// no_allocator!(); | ||||||||
| /// | ||||||||
| /// middleware_program_entrypoint!(hot,cold); | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| /// | ||||||||
| /// // This uses 4 CUs | ||||||||
| /// #[inline(always)] | ||||||||
| /// pub fn hot(input: *mut u8) -> u64 { | ||||||||
| /// unsafe { *input as u64 } | ||||||||
| /// } | ||||||||
| /// | ||||||||
| /// // This uses 113 CUs | ||||||||
| /// #[cold] | ||||||||
| /// #[inline(always)] | ||||||||
| /// pub fn cold( | ||||||||
| /// _program_id: &Pubkey, | ||||||||
| /// _accounts: &[AccountInfo], | ||||||||
| /// _instruction_data: &[u8], | ||||||||
| /// ) -> ProgramResult { | ||||||||
| /// msg!("Hello from Pinocchio!"); | ||||||||
| /// Ok(()) | ||||||||
| /// } | ||||||||
| /// ``` | ||||||||
| #[macro_export] | ||||||||
| macro_rules! middleware_program_entrypoint { | ||||||||
| ($hot:expr, $cold:expr) => { | ||||||||
| $crate::middleware_program_entrypoint!($hot, $cold, { $crate::MAX_TX_ACCOUNTS }); | ||||||||
| }; | ||||||||
| ($hot:expr, $cold:expr, $maximum:expr ) => { | ||||||||
|
|
||||||||
| #[no_mangle] | ||||||||
| pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 { | ||||||||
| if $hot(input) == 0 { | ||||||||
| return $crate::SUCCESS | ||||||||
| } | ||||||||
|
|
||||||||
| const UNINIT: core::mem::MaybeUninit<$crate::account_info::AccountInfo> = core::mem::MaybeUninit::<$crate::account_info::AccountInfo>::uninit(); | ||||||||
| // Create an array of uninitialized account infos. | ||||||||
| let mut accounts = [UNINIT; $maximum]; | ||||||||
|
|
||||||||
| let (program_id, count, instruction_data) = unsafe { | ||||||||
| $crate::entrypoint::deserialize::<$maximum>(input, &mut accounts) }; | ||||||||
|
|
||||||||
| // Call the program's entrypoint passing `count` account infos; we know that | ||||||||
| // they are initialized so we cast the pointer to a slice of `[AccountInfo]`. | ||||||||
| match $cold( | ||||||||
| &program_id, | ||||||||
| unsafe { core::slice::from_raw_parts(accounts.as_ptr() as _, count) }, | ||||||||
| &instruction_data, | ||||||||
| ) { | ||||||||
| Ok(()) => $crate::SUCCESS, | ||||||||
| Err(error) => error.into(), | ||||||||
| } | ||||||||
| } | ||||||||
| }; | ||||||||
| } | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.