0

I want to store data in data account owned by my custom program. Data structure is very simple - just Vec<PublicKey>

I can use pda but I'm worried its space should be set when being initialized. It's a little hard for me to set maximum count of PublicKey. I mean data accounts may have different size. So I wanted to create data account in web3 so that we can set space prior. Then program just need to write and read.

The data should be able to be written or read from program, and can be read from web3.

Can someone guide me or give similar example please?

1 Answer 1

0

Anchor appears to offer the ability to reallocate accounts using the realloc constraint. Depending on how you want to populate your Vec<Pubkey>, you could do it one at a time and reallocate 32 bytes each time, starting with 4 bytes to store the length.

There's a great example at https://beta.solpg.io/https://github.com/solana-developers/anchor-examples/tree/main/account-constraints/realloc, adapted a bit for your use case:

use anchor_lang::prelude::*;

declare_id!("8owLmone5oQWwAZPKeYEmMciBg8Q533UcHBjcU6niV9E");

#[program]
pub mod example {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        msg!("Initialize data to an empty vector");
        Ok(())
    }

    pub fn realloc(ctx: Context<Realloc>, input: Pubkey, new_number_of_pubkeys: usize) -> Result<()> {
        msg!("Add {input} to data, for a total of {new_number_of_pubkeys} pubkeys");
        ctx.accounts.existing_account.data.push(input);

        let data_size = ctx.accounts.existing_account.data.len();
        msg!("Account Data Size: {}", data_size);
        Ok(())
    }
}

#[derive(Accounts)]
#[instruction]
pub struct Initialize<'info> {
    #[account(mut)]
    pub signer: Signer<'info>,
    #[account(
        init, 
        payer = signer, 
        space = 8 + 4,
    )]
    pub new_account: Account<'info, DataAccount>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
#[instruction(input: Pubkey, new_number_of_pubkeys: usize)]
pub struct Realloc<'info> {
    #[account(mut)]
    pub signer: Signer<'info>,
    #[account(
        mut,
        realloc = 8 + 4 + new_number_of_pubkeys * 32,
        realloc::payer = signer,
        realloc::zero = false,
    )]
    pub existing_account: Account<'info, DataAccount>,
    pub system_program: Program<'info, System>,
}

#[account]
pub struct DataAccount {
    data: Vec<Pubkey>, 
}

Note that this is a bit goofy since it requires passing the new size. There might be a slicker way to do that based on the current size of the account, but I'm not familiar enough with Anchor to know if that's possible.

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.