Box Accounts
Box
ing accounts in #[Accounts]
struct moves the account variables from the stack to the heap.
This however requires you to be able to deserialize the account with an #[account]
type.
Eg
account: UncheckedAccount<'info>
becomes
account: Box<Account<'info, MyAccount>>
The trade-off is it will use more compute units to deserialize and validate the account data.
remaining_accounts
If you can't Box
and deserialize accounts (they're SystemProgram
owned, or you're too lazy to write out the serialization format), then don't include the account explicitly in #[Accounts]
and manually pull it out of ctx.remaining_accounts
in the body.
#[inline(never)]
The 4KB limit is on each stack frame. Each function call uses 1 stack frame, so if you have a beefy function it could very well exceed 4KB in stack space.
One trick is to break apart the function into sub-functions, then annotate the sub-functions with #[inline(never)]
macro.
This
fn big() {
// Do stuff 1
// Do stuff 2
// Do stuff 3
}
becomes
#[inline(never)]
fn stuff1() {
// Do stuff 1
}
#[inline(never)]
fn stuff2() {
// Do stuff 2
}
#[inline(never)]
fn stuff3() {
// Do stuff 3
}
fn big() {
stuff1();
stuff2();
stuff3();
}
Boxing variables
If you have functions that allocate large structs, Box::new()
will move them from the stack to the heap.