Skip to content

Commit 89cec9e

Browse files
committed
using pod and better alignment (was wasting some space for padding that wasn't needed)
1 parent 8b9248e commit 89cec9e

File tree

7 files changed

+147
-105
lines changed

7 files changed

+147
-105
lines changed

svm/programs/executor-quoter-router/src/instructions/initialize.rs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//!
33
//! Creates the Config PDA with the executor program ID and our chain ID.
44
5+
use bytemuck::{Pod, Zeroable};
56
use pinocchio::{
67
account_info::AccountInfo,
78
instruction::{Seed, Signer},
@@ -17,10 +18,20 @@ use crate::{
1718
state::{Config, CONFIG_DISCRIMINATOR, CONFIG_SEED},
1819
};
1920

20-
/// Initialize instruction data layout:
21-
/// - executor_program_id: Pubkey (32 bytes)
22-
/// - our_chain: u16 le (2 bytes)
23-
/// - bump: u8 (1 byte)
21+
/// Instruction data for Initialize.
22+
#[repr(C)]
23+
#[derive(Pod, Zeroable, Clone, Copy)]
24+
pub struct InitializeData {
25+
pub executor_program_id: Pubkey,
26+
pub our_chain: u16,
27+
pub bump: u8,
28+
pub _padding: u8,
29+
}
30+
31+
impl InitializeData {
32+
pub const LEN: usize = core::mem::size_of::<Self>();
33+
}
34+
2435
pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
2536
// Parse accounts
2637
let [payer, config_account, _system_program] = accounts else {
@@ -33,19 +44,17 @@ pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8]) -> Pr
3344
}
3445

3546
// Parse instruction data
36-
if data.len() < 35 {
47+
if data.len() < InitializeData::LEN {
3748
return Err(ExecutorQuoterRouterError::InvalidInstructionData.into());
3849
}
3950

40-
let executor_program_id: Pubkey = data[0..32]
41-
.try_into()
42-
.map_err(|_| ExecutorQuoterRouterError::InvalidInstructionData)?;
43-
44-
let mut our_chain_bytes = [0u8; 2];
45-
our_chain_bytes.copy_from_slice(&data[32..34]);
46-
let our_chain = u16::from_le_bytes(our_chain_bytes);
51+
let ix_data: InitializeData =
52+
bytemuck::try_pod_read_unaligned(&data[..InitializeData::LEN])
53+
.map_err(|_| ExecutorQuoterRouterError::InvalidInstructionData)?;
4754

48-
let bump = data[34];
55+
let executor_program_id = ix_data.executor_program_id;
56+
let our_chain = ix_data.our_chain;
57+
let bump = ix_data.bump;
4958

5059
// Verify the config PDA
5160
let bump_seed = [bump];

svm/programs/executor-quoter-router/src/instructions/quote_execution.rs

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//!
33
//! Gets a quote from a registered quoter via CPI.
44
5+
use bytemuck::{Pod, Zeroable};
56
use pinocchio::{
67
account_info::AccountInfo, cpi::set_return_data, program_error::ProgramError, pubkey::Pubkey,
78
ProgramResult,
@@ -13,31 +14,41 @@ use crate::{
1314
state::{load_account, QuoterRegistration},
1415
};
1516

17+
/// Fixed header for QuoteExecution instruction data.
18+
/// Variable-length fields (request_bytes, relay_instructions) follow after.
19+
#[repr(C)]
20+
#[derive(Pod, Zeroable, Clone, Copy)]
21+
pub struct QuoteExecutionHeader {
22+
pub quoter_address: [u8; 20],
23+
pub dst_chain: u16,
24+
pub dst_addr: [u8; 32],
25+
pub refund_addr: [u8; 32],
26+
pub _padding: [u8; 2],
27+
pub request_bytes_len: u32,
28+
}
29+
30+
impl QuoteExecutionHeader {
31+
pub const LEN: usize = core::mem::size_of::<Self>();
32+
}
33+
1634
/// QuoteExecution instruction.
1735
///
1836
/// Accounts:
1937
/// 0. `[]` quoter_registration - QuoterRegistration PDA for the quoter
2038
/// 1. `[]` quoter_program - The quoter implementation program
2139
/// 2-4. `[]` quoter accounts: config, chain_info, quote_body (passed to quoter)
22-
///
23-
/// Instruction data layout:
24-
/// - quoter_address: [u8; 20] (20 bytes) - The quoter address to look up
25-
/// - dst_chain: u16 le (2 bytes)
26-
/// - dst_addr: [u8; 32] (32 bytes)
27-
/// - refund_addr: [u8; 32] (32 bytes)
28-
/// - request_bytes_len: u32 le (4 bytes)
29-
/// - request_bytes: [u8; request_bytes_len]
30-
/// - relay_instructions_len: u32 le (4 bytes)
31-
/// - relay_instructions: [u8; relay_instructions_len]
3240
pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
33-
// Minimum data: 20 + 2 + 32 + 32 + 4 + 4 = 94 bytes
34-
if data.len() < 94 {
41+
// Minimum: header (90) + relay_instructions_len (4) = 94 bytes
42+
if data.len() < QuoteExecutionHeader::LEN + 4 {
3543
return Err(ExecutorQuoterRouterError::InvalidInstructionData.into());
3644
}
3745

38-
// Parse quoter_address from instruction data
39-
let mut quoter_address = [0u8; 20];
40-
quoter_address.copy_from_slice(&data[0..20]);
46+
// Parse fixed header
47+
let header: QuoteExecutionHeader =
48+
bytemuck::try_pod_read_unaligned(&data[..QuoteExecutionHeader::LEN])
49+
.map_err(|_| ExecutorQuoterRouterError::InvalidInstructionData)?;
50+
51+
let quoter_address = header.quoter_address;
4152

4253
// Parse accounts
4354
let [quoter_registration_account, quoter_program, quoter_config, quoter_chain_info, quoter_quote_body] =
@@ -59,16 +70,40 @@ pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8]) -> Pr
5970
return Err(ExecutorQuoterRouterError::QuoterNotRegistered.into());
6071
}
6172

73+
// Parse variable-length fields after header
74+
let request_bytes_len = header.request_bytes_len as usize;
75+
let request_bytes_start = QuoteExecutionHeader::LEN;
76+
let request_bytes_end = request_bytes_start + request_bytes_len;
77+
78+
if data.len() < request_bytes_end + 4 {
79+
return Err(ExecutorQuoterRouterError::InvalidInstructionData.into());
80+
}
81+
82+
let request_bytes = &data[request_bytes_start..request_bytes_end];
83+
84+
let relay_len_start = request_bytes_end;
85+
let relay_instructions_len = u32::from_le_bytes(
86+
data[relay_len_start..relay_len_start + 4]
87+
.try_into()
88+
.map_err(|_| ExecutorQuoterRouterError::InvalidInstructionData)?,
89+
) as usize;
90+
91+
let relay_instructions_start = relay_len_start + 4;
92+
let relay_instructions_end = relay_instructions_start + relay_instructions_len;
93+
94+
if data.len() < relay_instructions_end {
95+
return Err(ExecutorQuoterRouterError::InvalidInstructionData.into());
96+
}
97+
98+
let relay_instructions = &data[relay_instructions_start..relay_instructions_end];
99+
62100
// Build CPI instruction data for RequestQuote
63-
// Skip the quoter_address (20 bytes) and use the rest as the quoter instruction data
64101
let quoter_ix_data = make_quoter_request_quote_ix(
65-
u16::from_le_bytes([data[20], data[21]]), // dst_chain
66-
data[22..54].try_into().unwrap(), // dst_addr
67-
data[54..86].try_into().unwrap(), // refund_addr
68-
&data[90..90 + u32::from_le_bytes([data[86], data[87], data[88], data[89]]) as usize], // request_bytes
69-
&data[90
70-
+ u32::from_le_bytes([data[86], data[87], data[88], data[89]]) as usize
71-
+ 4..], // relay_instructions (simplified, should parse length properly)
102+
header.dst_chain,
103+
&header.dst_addr,
104+
&header.refund_addr,
105+
request_bytes,
106+
relay_instructions,
72107
);
73108

74109
// Invoke quoter's RequestQuote

svm/programs/executor-quoter-router/src/instructions/request_execution.rs

Lines changed: 50 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//! 3. Construct EQ02 signed quote
77
//! 4. CPI to Executor's request_for_execution
88
9+
use bytemuck::{Pod, Zeroable};
910
use pinocchio::{
1011
account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey, ProgramResult,
1112
};
@@ -18,6 +19,27 @@ use crate::{
1819
state::{load_account, Config, QuoterRegistration, EXPIRY_TIME_MAX},
1920
};
2021

22+
/// Fixed header for RequestExecution instruction data.
23+
/// Fields are ordered for optimal alignment (amount first as u64).
24+
/// Variable-length fields (request_bytes, relay_instructions) follow after.
25+
/// Total size: 104 bytes (padded for u64 alignment).
26+
#[repr(C)]
27+
#[derive(Pod, Zeroable, Clone, Copy)]
28+
pub struct RequestExecutionHeader {
29+
pub amount: u64,
30+
pub quoter_address: [u8; 20],
31+
pub dst_chain: u16,
32+
pub dst_addr: [u8; 32],
33+
pub refund_addr: [u8; 32],
34+
pub _padding1: [u8; 2],
35+
pub request_bytes_len: u32,
36+
pub _padding2: [u8; 4],
37+
}
38+
39+
impl RequestExecutionHeader {
40+
pub const LEN: usize = core::mem::size_of::<Self>();
41+
}
42+
2143
/// RequestExecution instruction.
2244
///
2345
/// Accounts:
@@ -30,67 +52,49 @@ use crate::{
3052
/// 6. `[writable]` refund_addr - Receives any excess payment
3153
/// 7. `[]` system_program
3254
/// 8-11. `[]` quoter accounts: quoter_config, chain_info, quote_body, event_cpi
33-
///
34-
/// Instruction data layout:
35-
/// - quoter_address: [u8; 20] (20 bytes)
36-
/// - amount: u64 le (8 bytes) - The amount being paid (msg.value equivalent)
37-
/// - dst_chain: u16 le (2 bytes)
38-
/// - dst_addr: [u8; 32] (32 bytes)
39-
/// - refund_addr_bytes: [u8; 32] (32 bytes) - Universal address for refund
40-
/// - request_bytes_len: u32 le (4 bytes)
41-
/// - request_bytes: [u8; request_bytes_len]
42-
/// - relay_instructions_len: u32 le (4 bytes)
43-
/// - relay_instructions: [u8; relay_instructions_len]
4455
pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], data: &[u8]) -> ProgramResult {
45-
// Minimum data: 20 + 8 + 2 + 32 + 32 + 4 + 4 = 102 bytes
46-
if data.len() < 102 {
56+
// Minimum: header (98) + relay_instructions_len (4) = 102 bytes
57+
if data.len() < RequestExecutionHeader::LEN + 4 {
4758
return Err(ExecutorQuoterRouterError::InvalidInstructionData.into());
4859
}
4960

50-
// Parse quoter_address
51-
let mut quoter_address = [0u8; 20];
52-
quoter_address.copy_from_slice(&data[0..20]);
61+
// Parse fixed header
62+
let header: RequestExecutionHeader =
63+
bytemuck::try_pod_read_unaligned(&data[..RequestExecutionHeader::LEN])
64+
.map_err(|_| ExecutorQuoterRouterError::InvalidInstructionData)?;
5365

54-
// Parse amount
55-
let mut amount_bytes = [0u8; 8];
56-
amount_bytes.copy_from_slice(&data[20..28]);
57-
let amount = u64::from_le_bytes(amount_bytes);
66+
let amount = header.amount;
67+
let quoter_address = header.quoter_address;
68+
let dst_chain = header.dst_chain;
69+
let dst_addr = header.dst_addr;
70+
let refund_addr_bytes = header.refund_addr;
5871

59-
// Parse dst_chain
60-
let mut dst_chain_bytes = [0u8; 2];
61-
dst_chain_bytes.copy_from_slice(&data[28..30]);
62-
let dst_chain = u16::from_le_bytes(dst_chain_bytes);
72+
// Parse variable-length fields after header
73+
let request_bytes_len = header.request_bytes_len as usize;
74+
let request_bytes_start = RequestExecutionHeader::LEN;
75+
let request_bytes_end = request_bytes_start + request_bytes_len;
6376

64-
// Parse dst_addr
65-
let mut dst_addr = [0u8; 32];
66-
dst_addr.copy_from_slice(&data[30..62]);
67-
68-
// Parse refund_addr_bytes
69-
let mut refund_addr_bytes = [0u8; 32];
70-
refund_addr_bytes.copy_from_slice(&data[62..94]);
71-
72-
// Parse request_bytes
73-
let mut request_bytes_len_arr = [0u8; 4];
74-
request_bytes_len_arr.copy_from_slice(&data[94..98]);
75-
let request_bytes_len = u32::from_le_bytes(request_bytes_len_arr) as usize;
76-
77-
if data.len() < 98 + request_bytes_len + 4 {
77+
if data.len() < request_bytes_end + 4 {
7878
return Err(ExecutorQuoterRouterError::InvalidInstructionData.into());
7979
}
8080

81-
let request_bytes = &data[98..98 + request_bytes_len];
81+
let request_bytes = &data[request_bytes_start..request_bytes_end];
82+
83+
let relay_len_start = request_bytes_end;
84+
let relay_instructions_len = u32::from_le_bytes(
85+
data[relay_len_start..relay_len_start + 4]
86+
.try_into()
87+
.map_err(|_| ExecutorQuoterRouterError::InvalidInstructionData)?,
88+
) as usize;
8289

83-
// Parse relay_instructions
84-
let relay_start = 98 + request_bytes_len;
85-
let mut relay_len_arr = [0u8; 4];
86-
relay_len_arr.copy_from_slice(&data[relay_start..relay_start + 4]);
87-
let relay_instructions_len = u32::from_le_bytes(relay_len_arr) as usize;
90+
let relay_instructions_start = relay_len_start + 4;
91+
let relay_instructions_end = relay_instructions_start + relay_instructions_len;
8892

89-
if data.len() < relay_start + 4 + relay_instructions_len {
93+
if data.len() < relay_instructions_end {
9094
return Err(ExecutorQuoterRouterError::InvalidInstructionData.into());
9195
}
9296

93-
let relay_instructions = &data[relay_start + 4..relay_start + 4 + relay_instructions_len];
97+
let relay_instructions = &data[relay_instructions_start..relay_instructions_end];
9498

9599
// Parse accounts
96100
let [payer, config_account, quoter_registration_account, quoter_program, _executor_program, payee, refund_account, system_program, quoter_config, quoter_chain_info, quoter_quote_body, event_cpi] =

0 commit comments

Comments
 (0)