Skip to content

Instantly share code, notes, and snippets.

@wedancedalot
Last active August 29, 2022 18:29
Show Gist options
  • Save wedancedalot/45678b4b70fb6e178af07b773b31be91 to your computer and use it in GitHub Desktop.
Save wedancedalot/45678b4b70fb6e178af07b773b31be91 to your computer and use it in GitHub Desktop.
Migrate state Anchor Solana (with reallocation)
use std::io::Write;
use anchor_lang::{prelude::*, solana_program::{entrypoint::ProgramResult}};
/// Old state
#[account]
pub struct ConfigDeprecated {
pub initial_field: Pubkey,
}
impl ConfigDeprecated {
pub const LEN: usize = 8 + (32);
}
/// New state to be migrated, with additional field
#[account]
pub struct Config {
pub initial_field: Pubkey,
pub one_more_field: Pubkey,
}
impl Config {
pub const LEN: usize = 8 + (32 + 32);
}
#[derive(Accounts)]
pub struct Migrate<'info> {
/// CHECK: don't forget to make all necessary checks
#[account(mut)]
pub config: UncheckedAccount<'info>,
#[account(mut)]
pub payer: Signer<'info>,
pub system_program: Program<'info, System>,
pub rent: Sysvar<'info, Rent>,
}
impl<'info> Migrate<'info> {
fn realloc_and_rent(&self, new_len: usize) -> ProgramResult {
// Realloc
self.config.realloc(new_len, false)?;
let balance = self.config.lamports();
if self.rent.is_exempt(balance, new_len) {
return Ok(());
}
// Transfer some lamports
let min_balance = self.rent.minimum_balance(new_len);
if balance.ge(&min_balance) {
return Ok(());
}
let ix = anchor_lang::solana_program::system_instruction::transfer(
&self.payer.key(),
&self.config.key(),
min_balance - balance,
);
anchor_lang::solana_program::program::invoke(
&ix,
&[
self.payer.to_account_info(),
self.config.to_account_info(),
],
)
}
}
pub fn migrate(ctx: Context<Migrate>, new_field: Pubkey) -> Result<()> {
let deprecated_config = ConfigDeprecated::try_deserialize_unchecked(&mut ctx.accounts.config.try_borrow_data()?.as_ref())?;
let new_data = Config{
initial_field: deprecated_config.initial_field,
one_more_field: new_field,
};
let mut buffer: Vec<u8> = Vec::new();
new_data.try_serialize(&mut buffer)?;
if buffer.len() != Config::LEN {
return err!(AccountDidNotSerialize)
}
ctx.accounts.realloc_and_rent(Config::LEN)?;
ctx.accounts.config.try_borrow_mut_data()?.write_all(&buffer)?;
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment