
secondary title
1. Necessity of contract upgrade
secondary title
2. Common upgrade methods for Solidity contracts
In Ethereum, smart contracts are immutable, once deployed on the chain, no one can change it.
So if there are loopholes in the contract or the contract needs to add new functions, how to modify the code of the contract? The solution is to deploy new contracts to the blockchain.
The challenge of this method is that each time Solidity deploys a contract, the contract will be assigned a unique address. Therefore, all DApps that use this contract need to modify the contract address to adapt to the new contract. In addition, the state in the old version of the contract needs to be migrated to the new version of the contract. The migration of contracts with more complex states requires a lot of work, is prone to errors, and the gas cost of copying data is high.
Therefore, we usually adopt an architecture where data and logic are separated, and data is stored in a contract (state contract) that does not process any logic, and all logic is implemented in another contract (logic contract). Usually contract upgrades modify the logic. Using this architecture only needs to upgrade the logic contract without worrying about state migration.
In order to solve this problem, a proxy contract (Proxy Contract) can be used, and the specific structure is shown in the figure below.
The proxy contract is used to store data, and delegatecall is used to call logic contract A, so that the data read and written by contract A is stored in the proxy contract. If you need to upgrade the logic contract, deploy a new contract B, and then send a transaction to the proxy contract, so that the proxy contract points to the new logic contract B.
3. Common methods of NEAR contract upgrade
Next, we will take the StatusMessage project as an example to introduce the common upgrade methods of the NEAR contract. The contract code of StatusMessage is as follows
We first deploy the compiled contract on the test network.
The transaction is as follows
Then we call the set_status method to store data in the contract
The transaction is as follows
Next we discuss in detail two different contract upgrade scenarios
3.1 The contract data structure has not been modified
For example, we add a function:
After compiling, use deploy to redeploy:
After compiling, use deploy to redeploy:
Then we call the get_status method to read the previously written data
The data in the original contract can be read successfully:
This is because the NEAR contract can be deployed repeatedly. If an account (address) has already deployed the contract, calling the near deploy command again can deploy the new contract code to the account. If we only modify the contract logic without modifying the data structure, we can directly use near deploy to deploy new code.
3.2 The contract data structure is modified
We upgraded the contract, modified the original data structure, removed records, added taglines and bios
We try to redeploy again:
The contract is still successfully deployed:
But we call the get_tagline method to read the stored data:
You will find that something went wrong, and the error message is as follows:
Cannot deserialize the contract state.
See the specific transaction:
https://explorer.testnet.near.org/transactions/4hQQ1zAwU5bsbfb6tA6DQDqjmFcHsBwaBctdHaPiCKHu
This is because the state of the contract is persistently stored in the form of serialized data. After the contract is redeployed, the data structure in the code changes but the state remains unchanged. If the new data structure does not match the old state, an error occurs.
3.3 Migrate upgrade smart contract
NEAR provides the Migrate method to help us upgrade the contract. For the errors in 3.2, we add the migrate method to the new contract:
#[init(ignore_state)] in the code means not to load the state before the migrate function is executed. Next, we redeploy the contract, but call the migrate method while deploying
As shown below, the contract is successfully deployed:
We try to call the new method get_tagline of the contract to get the new data taglines
It can be seen that the method is successfully called, and the old contract data is also migrated to the new contract
4. Security considerations for contract upgrades
Contract security upgrades must first consider authority control. Generally, contracts can only be upgraded by developers or DAO. last termRust Smart Contract Cultivation Diary (8) Authority Control of Contract SecurityIntroduces the access control of privileged functions. The upgrade function of a general contract is the only owner function, ensuring that it can only be called by the owner.
We recommend setting the owner of the contract as DAO as much as possible, and jointly manage the contract through proposals and voting. Because the owner is set as a personal account, the contract is highly centralized, the owner can modify the contract data at will, and there is also the risk of losing the owner's private key.
In addition, developers can also consider the following suggestions when doing contract migration
Add #[init(ignore_state)] before the migration function to ensure that the state is not loaded before the migration function is executed.
After the migration is complete, delete the migration function as much as possible to ensure that the migration function is called only once.
The newly added data structure is initialized during migration.