1

Let us suppose users are able to create a program-owned-account: PurchaseItemAccount, which is deployed as:

{
  id: u64 
  price: u64
}

After some time, I then decide to add a field, purchase_timestamp, to this account:

{
  id: u64 
  price: u64
  purchase_timestamp: i64
}
  1. If I try to access purchase_timestamp of the old accounts (before the upgrade), will I just get an error?
  2. And vice versa, if I try to access the new accounts that were created post-upgrade, I will succeed?
  3. So to handle such an upgrade properly I would need to do some extra error handling?

2 Answers 2

1

To answer your questions directly:

  1. If I try to access purchase_timestamp of the old accounts (before the upgrade), will I just get an error?

Correct, your program will fail to deserialize the old accounts, since your program expects additional data in the account, and it isn't there.

  1. And vice versa, if I try to access the new accounts that were created post-upgrade, I will succeed?

Yep! Assuming those accounts are created with the new field, of course.

  1. So to handle such an upgrade properly I would need to do some extra error handling?

That's one option certainly -- you check the size, and deserialize it as the old type if it's smaller, and as the new type if it's larger.

Your other options:

  • introduce a totally new account type for the expanded accounts. This causes more churn since you probably need to add new instructions to handle the old and new types
  • add a permissionless instruction to "upgrade" the old accounts to the new type. In that case, the instruction reallocates the account to the new size and transfers enough lamports to cover the higher rent-exemption on the expanded accounts. Once the instruction exists, you upgrade your program and quickly run your new instruction on all accounts.
1

There's a Solana cookbook page on this: https://solanacookbook.com/guides/data-migration.html#scenario

If you're using ZeroCopy then you can add a field and chunk off bytes as you create new fields.

#[account(zero_copy)]
#[repr(packed)]
pub struct MyStateV1 {
    pub authority: Pubkey,
    /// Reserved for future info.
    pub _ebuf: [u8; 1024],
}

#[account(zero_copy)]
#[repr(packed)]
pub struct MyStateV2 {
    pub authority: Pubkey,
    pub new_field: u64,
    /// Reserved for future info.
    pub _ebuf: [u8; 1016],
}

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.