Schema Migration | NEAR Welcome Track
Upgrading Contracts: Production App Basics | NEAR SDK docs
일반적인 코드 수정은, 해당 contract를 담고 있는 계정(ex. contract.testnet)에 Full Access Key로 재배포하면 되지만, 만약 struct 등, state와 관련된 코드를 수정후 재배포한다면,
해당 컨트랙트를 view 또는 call하는 호출을 만들면 아래와 같은 패닉을 마주한다.
Cannot deserialize the contract state.
이 경우, old contract의 state를 migration하는 과정이 필요하다.
pub struct OldContract {
token: FungibleToken,
metadata: LazyOption<FungibleTokenMetadata>,
}
->
pub struct NewContract {
token: FungibleToken,
metadata: LazyOption<FungibleTokenMetadata>,
controller:AccountId,
}
위와 같이, Contract struct를 수정한 경우,
#[private]
#[init(ignore_state)]
pub fn migrate() -> Self {
#[derive(BorshDeserialize)]
pub struct OldContract {
token: FungibleToken,
metadata: LazyOption<FungibleTokenMetadata>,
}
let old: OldContract = env::state_read().unwrap();
Self {
token: old.token,
metadata: old.metadata.into(),
controller:env::predecessor_account_id(),
}
}
이전 old state를 불러온 후에, 새로운 Contract struct는 불러온 old state에 추가할 필드(controller)를 추가하여 만들면 된다.
near deploy --wasmFile out/main.wasm --initFunction "migrate" --initArgs "{}" --accountId $ID
마지막으로 컨트랙트를 contract.testnet에 재배포하면서, 동시에 migrate function을 실행하면 된다.
토큰의 메타데이터를 수정하고 싶은 경우
#[private]
#[init(ignore_state)]
pub fn migrate_metadata(
metadata: FungibleTokenMetadata,
) -> Self {
#[derive(BorshDeserialize)]
pub struct OldContract {
token: FungibleToken,
metadata: LazyOption<FungibleTokenMetadata>,
controller:AccountId,
}
let old: OldContract = env::state_read().unwrap();
metadata.assert_valid();
Self {
token: old.token,
metadata: LazyOption::new(b"m".to_vec(), Some(&metadata)),
controller:old.controller,
}
}
역시 old state를 불러오고, 수정된 metadata를 추가하면 된다.
export ICON=data:image/svg+xml,%3Csvg xmlns='<http://www.w3.org/2000/svg>' viewBox='0 0 1514.28 1514.28'%3E%3Cdefs%3E%3ClinearGradient id='d' x1='102.19' y1='379.01' x2='1412.09' y2='1135.28' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%23c922ee'/%3E%3Cstop offset='.08' stop-color='%23bf20e9'/%3E%3Cstop offset='.2' stop-color='%23a61bdd'/%3E%3Cstop offset='.37' stop-color='%237c14ca'/%3E%3Cstop offset='.56' stop-color='%23430aaf'/%3E%3Cstop offset='.57' stop-color='%23400aae'/%3E%3Cstop offset='.87' stop-color='%239a1dd9'/%3E%3Cstop offset='.99' stop-color='%23b824e7'/%3E%3C/linearGradient%3E%3ClinearGradient id='e' x1='274.03' y1='1240.25' x2='1240.25' y2='274.03' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%232e048e'/%3E%3Cstop offset='.15' stop-color='%23280497'/%3E%3Cstop offset='.24' stop-color='%232404a0'/%3E%3Cstop offset='.45' stop-color='%233507a8'/%3E%3Cstop offset='.57' stop-color='%23400aae'/%3E%3Cstop offset='.87' stop-color='%239a1dd9'/%3E%3Cstop offset='.99' stop-color='%23b824e7'/%3E%3C/linearGradient%3E%3Cfilter id='f' filterUnits='userSpaceOnUse'%3E%3CfeOffset dx='7' dy='7'/%3E%3CfeGaussianBlur result='g' stdDeviation='5'/%3E%3CfeFlood flood-color='%23000' flood-opacity='.75'/%3E%3CfeComposite in2='g' operator='in'/%3E%3CfeComposite in='SourceGraphic'/%3E%3C/filter%3E%3Cstyle%3E.i%7Bstroke:%23140a96;stroke-miterlimit:10;fill:%23c821ed;stroke-width:4px%7D%3C/style%3E%3C/defs%3E%3Cg id='b'%3E%3Cg id='c'%3E%3Ccircle cx='757.14' cy='757.14' r='756.14' style='fill:url(%23d);stroke-width:2px;stroke:%23140a96;stroke-miterlimit:10'/%3E%3Ccircle cx='757.14' cy='757.14' r='683.22' style='stroke-width:2px;stroke:%23140a96;stroke-miterlimit:10;fill:url(%23e)'/%3E%3Ccircle class='i' cx='757.14' cy='757.14' r='614.9'/%3E%3Ccircle class='i' cx='757.14' cy='757.14' r='572.47'/%3E%3Cpath d='M1230.91 757.14c-373.28 55.5-418.27 100.5-473.77 473.77-55.5-373.28-100.5-418.27-473.77-473.77 373.28-55.5 418.27-100.5 473.77-473.77 55.5 373.28 100.5 418.27 473.77 473.77Z' style='fill:%23fff;filter:url(%23f)'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E
near deploy --wasmFile out/main.wasm --initFunction "migrate_metadata" --initArgs '{"metadata": { "spec": "ft-1.0.0", "name": "Tracer Utility Token", "symbol": "TRC", "icon": "'$ICON'", "decimals": 4 }}' --accountId $ID
컨트랙트를 contract.testnet에 재배포하면서, 동시에 수정할 metadata를 arguments에 담아 migrate_metadata function을 실행하면 된다.