2

I've an account like this:

#[account]
#[derive(Default, InitSpace)]
pub struct Blacklist {
    pub access_controller: Pubkey,

    #[max_len(318)]                 // that touches realloc limit 10KB
    pub addresses: Vec<Pubkey>,
}

I use this to blacklist addresses and when it consumes all the initial allocation 10212 bytes (which is little less than the realloc limit 10KB), then I realloc additional 10KB; now I can add roughly 320 more elements to the vector. But when the vector's len is 512 (which is its capacity as well), it needs to expand which causes:

Error: memory allocation failed, out of memory

I probably understand why it gives this error because the program cannot allocate more than 32KB of memory, which is the max heap size of allocator an instruction can use, as per the Solana docs.

Programs have access to a runtime heap either directly in C or via the Rust alloc APIs. To facilitate fast allocations, a simple 32KB bump heap is utilized. The heap does not support free or realloc so use it wisely.

Now my question is, if the heap max size is 32KB only and it cannot grow bigger than that, then how can an account ever grow to 10MB which is the limit of the account size?

2 Answers 2

3

Simple answer: accounts are not allocated on the heap, but rather passed in as bytes directly to the instruction, in a separate area of memory.

If you use borsh to deserialize your type from the account data, however, it will allocate the vector on the heap. To get around this, you'll need to do some in-place deserialization, ie. reinterpreting the bytes directly from the account data byte slice.

Since they're all pubkeys, you can do this quite easily with the bytemuck crate. Here's an example of PodSlice which gives exactly the functionality that you need: https://github.com/solana-labs/solana-program-library/blob/b33a0ab988ad0d2157a0159d41664e06931c338e/libraries/tlv-account-resolution/src/pod.rs#L92

2

If you use a fixed-length array of Pubkeys instead, and the rest of your struct is POD that supports zero-copy, then you will be able to allocate up to 10MB. AccountLoader can de-serialize these large accounts for you without hitting the heap. More info: https://docs.rs/anchor-lang/latest/anchor_lang/attr.account.html

Generally you'll use a placeholder key like Pubkey::default() for the unused items.

The disadvantage is obviously that you need to know how large your list will be and allocate all the rent up front. However, if you run out of space, you can always close the account and copy the items to a new one with a larger size.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.