Updating Contracts
NEAR 계정은 로직(컨트랙트의 코드)을 상태(스토리지)와 분리하여, 코드를 변경할 수 있습니다.
컨트랙트는 두 가지 방법으로 업데이트할 수 있습니다.
- Through tools such as NEAR CLI or near-api-js (if you hold the account's full access key).
- Programmatically, by implementing a method that takes the new code and deploys it.
Updating Through Tools
NEAR CLI 등 선호하는 도구를 사용하여 다른 컨트랙트를 재배포하기만 하면 됩니다.
- near-cli
- near-cli-rs
# (optional) If you don't have an account, create one
near create-account <account-id> --useFaucet
# Deploy the contract
near deploy <account-id> <wasm-file>
# (optional) If you don't have an account, create one
near account create-account sponsor-by-faucet-service somrnd.testnet autogenerate-new-keypair save-to-keychain network-config testnet create
# Deploy the contract
near contract deploy <accountId> use-file <route_to_wasm> without-init-call network-config testnet sign-with-keychain send
프로그래밍을 통한 업데이트
스마트 컨트랙트를 다음과 같은 방법을 구현하여 자체적으로 업데이트할 수도 있습니다.
- Takes the new wasm contract as input
- Promise를 생성하여 자체적으로 배포합니다.
- 🦀 Rust
loading...
How to Invoke Such Method?
- near-cli
- near-cli-rs
- 🌐 JavaScript
# Load the contract's raw bytes
CONTRACT_BYTES=`cat ./path/to/wasm.wasm | base64`
# Call the update_contract method
near call <contract-account> update_contract "$CONTRACT_BYTES" --base64 --accountId <manager-account> --gas 300000000000000
# Call the update_contract method
near contract call-function as-transaction <contract-account> update_contract file-args </path/to/wasm.wasm> prepaid-gas '300.0 Tgas' attached-deposit '0 NEAR' sign-as <manager-account> network-config testnet sign-with-keychain send
// Load the contract's raw bytes
const code = fs.readFileSync("./path/to/wasm.wasm");
// Call the update_contract method
await wallet.callMethod({contractId: guestBook, method: "update_contract", args: code, gas: "300000000000000"});
This is how DAO factories update their contracts
Migrating the State
Since the account's logic (smart contract) is separated from the account's state (storage), the account's state persists when re-deploying a contract.
Because of this, adding methods or modifying existing ones will yield no problems.
However, deploying a contract that modifies or removes structures stored in the state will raise an error: Cannot deserialize the contract state
, in which case you can choose to:
- 다른 계정 사용
- Rollback to the previous contract code
- 컨트랙트 상태를 마이그레이션하는 메서드 추가
마이그레이션 메서드
상태를 마이그레이션하는 것 외에 다른 옵션이 없는 경우 다음과 같은 메서드를 구현해야 합니다.
- Reads the current state of the contract
- 새로운 상태로 변환하기 위해 다른 함수를 적용합니다.
- 새로운 상태를 반환합니다.
이것이 DAO가 스스로를 업데이트하는 방법입니다.
예제: 방명록 마이그레이션
메시지를 저장하는 방명록이 있고, 사용자가 이러한 메시지에 대해 "프리미엄"으로 지불할 수 있다고 상상해 보세요. 다음과 같은 상태를 사용하여 메시지 및 결제를 추적할 수 있습니다.
- 🦀 Rust
loading...
컨트랙트 업데이트
만약 어느 시점에서 PostedMessage
내 payments
를 추적할 수 있다는 것을 깨달아서, 컨트랙트를 다음과 같이 변경했다고 해봅시다.
- 🦀 Rust
loading...
호환되지 않는 상태
초기화된 계정에 업데이트를 배포하면, 다음과 같은 이유로 컨트랙트는 계정 상태를 역직렬화하지 못합니다.
- (이전 컨트랙 트로부터) 상태에 저장된 추가
payments
벡터가 존재합니다. - 저장된
PostedMessages
에는 (이전 컨트랙트와 같이)payment
필드가 존재하지 않습니다.
Migrating the State
이 문제를 해결하려면, 이전 상태를 거쳐 payments
벡터를 제거하고, PostedMessages
에 정보를 추가하는 메서드를 구현해야 합니다.
- 🦀 Rust
loading...
실제로 migrate
는 기존 상태([#init(ignore_state)]
)를 무시하는
You can follow a migration step by step in the official migration example