Last active
August 29, 2022 18:29
-
-
Save wedancedalot/45678b4b70fb6e178af07b773b31be91 to your computer and use it in GitHub Desktop.
Migrate state Anchor Solana (with reallocation)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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