Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit 297c49e

Browse files
committed
Reduce batch compute units
1 parent 55ae87b commit 297c49e

File tree

3 files changed

+56
-43
lines changed

3 files changed

+56
-43
lines changed

program/src/entrypoint.rs

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use batch::process_batch;
21
use pinocchio::{
32
account_info::AccountInfo, default_panic_handler, no_allocator, program_entrypoint,
43
program_error::ProgramError, pubkey::Pubkey, ProgramResult,
@@ -12,6 +11,27 @@ no_allocator!();
1211
// Use the default panic handler.
1312
default_panic_handler!();
1413

14+
#[inline(always)]
15+
pub fn process_instruction(
16+
_program_id: &Pubkey,
17+
accounts: &[AccountInfo],
18+
instruction_data: &[u8],
19+
) -> ProgramResult {
20+
let [discriminator, instruction_data @ ..] = instruction_data else {
21+
return Err(ProgramError::InvalidInstructionData);
22+
};
23+
24+
if *discriminator == 255 {
25+
// 255 - Batch
26+
#[cfg(feature = "logging")]
27+
pinocchio::msg!("Instruction: Batch");
28+
29+
return process_batch(accounts, instruction_data);
30+
}
31+
32+
inner_process_instruction(accounts, instruction_data, *discriminator)
33+
}
34+
1535
/// Process an instruction.
1636
///
1737
/// The processor of the token program is divided into two parts to reduce the overhead
@@ -22,32 +42,35 @@ default_panic_handler!();
2242
///
2343
/// Instructions on the first part of the processor:
2444
///
25-
/// - `0`: `InitializeMint`
26-
/// - `3`: `Transfer`
27-
/// - `7`: `MintTo`
28-
/// - `9`: `CloseAccount`
45+
/// - `0`: `InitializeMint`
46+
/// - `1`: `InitializeAccount`
47+
/// - `3`: `Transfer`
48+
/// - `7`: `MintTo`
49+
/// - `9`: `CloseAccount`
50+
/// - `18`: `InitializeAccount2`
2951
/// - `18`: `InitializeAccount3`
3052
/// - `20`: `InitializeMint2`
31-
/// - `255`: `Batch`
3253
#[inline(always)]
33-
pub fn process_instruction(
34-
_program_id: &Pubkey,
54+
pub fn inner_process_instruction(
3555
accounts: &[AccountInfo],
3656
instruction_data: &[u8],
57+
discriminator: u8,
3758
) -> ProgramResult {
38-
let [discriminator, instruction_data @ ..] = instruction_data else {
39-
return Err(ProgramError::InvalidInstructionData);
40-
};
41-
42-
match *discriminator {
59+
match discriminator {
4360
// 0 - InitializeMint
4461
0 => {
4562
#[cfg(feature = "logging")]
4663
pinocchio::msg!("Instruction: InitializeMint");
4764

4865
process_initialize_mint(accounts, instruction_data, true)
4966
}
67+
// 1 - InitializeAccount
68+
1 => {
69+
#[cfg(feature = "logging")]
70+
pinocchio::msg!("Instruction: InitializeAccount");
5071

72+
process_initialize_account(accounts)
73+
}
5174
// 3 - Transfer
5275
3 => {
5376
#[cfg(feature = "logging")]
@@ -69,6 +92,13 @@ pub fn process_instruction(
6992

7093
process_close_account(accounts)
7194
}
95+
// 16 - InitializeAccount2
96+
16 => {
97+
#[cfg(feature = "logging")]
98+
pinocchio::msg!("Instruction: InitializeAccount2");
99+
100+
process_initialize_account2(accounts, instruction_data)
101+
}
72102
// 18 - InitializeAccount3
73103
18 => {
74104
#[cfg(feature = "logging")]
@@ -83,14 +113,7 @@ pub fn process_instruction(
83113

84114
process_initialize_mint2(accounts, instruction_data)
85115
}
86-
// 255 - Batch
87-
255 => {
88-
#[cfg(feature = "logging")]
89-
pinocchio::msg!("Instruction: Batch");
90-
91-
process_batch(accounts, instruction_data)
92-
}
93-
_ => process_remaining_instruction(accounts, instruction_data, *discriminator),
116+
_ => inner_process_remaining_instruction(accounts, instruction_data, discriminator),
94117
}
95118
}
96119

@@ -99,19 +122,12 @@ pub fn process_instruction(
99122
/// This function is called by the `process_instruction` function if the discriminator
100123
/// does not match any of the common instructions. This function is used to reduce the
101124
/// overhead of having a large `match` statement in the `process_instruction` function.
102-
fn process_remaining_instruction(
125+
fn inner_process_remaining_instruction(
103126
accounts: &[AccountInfo],
104127
instruction_data: &[u8],
105128
discriminator: u8,
106129
) -> ProgramResult {
107130
match discriminator {
108-
// 1 - InitializeAccount
109-
1 => {
110-
#[cfg(feature = "logging")]
111-
pinocchio::msg!("Instruction: InitializeAccount");
112-
113-
process_initialize_account(accounts)
114-
}
115131
// 2 - InitializeMultisig
116132
2 => {
117133
#[cfg(feature = "logging")]
@@ -189,13 +205,6 @@ fn process_remaining_instruction(
189205

190206
process_burn_checked(accounts, instruction_data)
191207
}
192-
// 16 - InitializeAccount2
193-
16 => {
194-
#[cfg(feature = "logging")]
195-
pinocchio::msg!("Instruction: InitializeAccount2");
196-
197-
process_initialize_account2(accounts, instruction_data)
198-
}
199208
// 17 - SyncNative
200209
17 => {
201210
#[cfg(feature = "logging")]

program/src/processor/batch.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use pinocchio::{account_info::AccountInfo, program_error::ProgramError, ProgramResult};
22

3-
use crate::entrypoint::process_instruction;
3+
use crate::entrypoint::inner_process_instruction;
44

55
/// The size of the batch instruction header.
66
///
@@ -18,11 +18,12 @@ pub fn process_batch(mut accounts: &[AccountInfo], mut instruction_data: &[u8])
1818
return Err(ProgramError::InvalidInstructionData);
1919
}
2020

21-
// SAFETY: The instruction data is guaranteed to have at least two bytes.
21+
// SAFETY: The instruction data is guaranteed to have at least two bytes (header)
22+
// + one byte (discriminator).
2223
let expected_accounts = unsafe { *instruction_data.get_unchecked(0) as usize };
2324
let data_offset = IX_HEADER_SIZE + unsafe { *instruction_data.get_unchecked(1) as usize };
2425

25-
if instruction_data.len() < data_offset {
26+
if instruction_data.len() < data_offset || data_offset == 0 {
2627
return Err(ProgramError::InvalidInstructionData);
2728
}
2829

@@ -32,10 +33,12 @@ pub fn process_batch(mut accounts: &[AccountInfo], mut instruction_data: &[u8])
3233

3334
// Process the instruction.
3435

35-
process_instruction(
36-
&token_interface::program::ID,
37-
&accounts[..expected_accounts],
38-
&instruction_data[IX_HEADER_SIZE..data_offset],
36+
// SAFETY: The instruction data and accounts lengths are already validated so all
37+
// the slices are guaranteed to be valid.
38+
inner_process_instruction(
39+
unsafe { accounts.get_unchecked(..expected_accounts) },
40+
unsafe { instruction_data.get_unchecked(IX_HEADER_SIZE + 1..data_offset) },
41+
unsafe { *instruction_data.get_unchecked(IX_HEADER_SIZE) },
3942
)?;
4043

4144
if data_offset == instruction_data.len() {

program/src/processor/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub mod shared;
5050
pub use amount_to_ui_amount::process_amount_to_ui_amount;
5151
pub use approve::process_approve;
5252
pub use approve_checked::process_approve_checked;
53+
pub use batch::process_batch;
5354
pub use burn::process_burn;
5455
pub use burn_checked::process_burn_checked;
5556
pub use close_account::process_close_account;

0 commit comments

Comments
 (0)