Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In NearProtocol, how to migrate contract state

Assume there's a contract written in near-sdk-rs, deployed, has state defined as:

#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize)]
pub struct NFT {
    pub tokens: UnorderedMap<TokenId, Token>,
}

#[derive(BorshDeserialize, BorshSerialize)]
pub struct Token {
   pub owner: AccountId
}

Now there're some usage of this contract, as a result some records of tokens stored on chain. Then I'd like to update this contract by adding a field to Token:

pub struct Token {
   pub owner: AccountId
   pub name: String // For existing ones, this will be set to ""
}

How to do this with existing state kept (similar of doing a database migration)?

like image 245
Bo Yao Avatar asked Apr 11 '21 05:04

Bo Yao


2 Answers

You can also see how some of the examples we've created use versioning.

See BerryClub:

#[derive(BorshDeserialize, BorshSerialize)]
pub struct AccountVersionAvocado {
    pub account_id: AccountId,
    pub account_index: AccountIndex,
    pub balance: u128,
    pub num_pixels: u32,
    pub claim_timestamp: u64,
}

impl From<AccountVersionAvocado> for Account {
    fn from(account: AccountVersionAvocado) -> Self {
        Self {
            account_id: account.account_id,
            account_index: account.account_index,
            balances: vec![account.balance, 0],
            num_pixels: account.num_pixels,
            claim_timestamp: account.claim_timestamp,
            farming_preference: Berry::Avocado,
        }
    }
}

https://github.com/evgenykuzyakov/berryclub/blob/ad2b37045b14fa72181ab92831fb741a7c40234b/contract-rs/pixel-board/src/account.rs#L19-L39

There are others but will have to come back to this once I find them

like image 161
amgando Avatar answered Oct 05 '22 04:10

amgando


So far I can only suggest to deploy a temporary contract with old Token struct kept as is, and NewToken implement NewToken::from_token, and a change method:

impl Token {
    pub fn migrate(&mut self) {
        near_sdk::env::storage_write(
            "STATE",
            NewToken::from_token(self).try_into_vec().unwrap()
        );
    }
}

After you migrate the state, you can deploy a contract with the NewToken instead of Token.

like image 38
Vlad Frolov Avatar answered Oct 05 '22 06:10

Vlad Frolov