實(shí)現(xiàn)可升級(jí)的智能合約需要使用一種特殊的設(shè)計(jì)模式,稱為"代理模式"。代理模式的核心思想是:使用一個(gè)代理合約來(lái)間接管理另一個(gè)合約,并且可以動(dòng)態(tài)更改管理的合約。
實(shí)現(xiàn)步驟如下:
代理模式需要使用一些特殊的技巧,但是它是一種非常有效的方法,可以使智能合約的代碼在不影響原有合約的情況下進(jìn)行升級(jí)。
舉例:
假設(shè)你正在開發(fā)一個(gè)投票系統(tǒng),該系統(tǒng)可以通過(guò)智能合約實(shí)現(xiàn),在投票時(shí),每個(gè)人都可以通過(guò)給智能合約發(fā)送交易來(lái)表示投票。
初始版本的智能合約代碼可能長(zhǎng)這樣:
pragma solidity ^0.8.0;
contract Vote {
uint256 public voteCount;
function vote() public {
voteCount += 1;
}
}
但是隨著時(shí)間的推移,你可能想要升級(jí)智能合約,以便實(shí)現(xiàn)更多功能,比如投票者必須通過(guò)身份驗(yàn)證才能投票。
你可以通過(guò)使用代理模式實(shí)現(xiàn)這個(gè)升級(jí),代理合約代碼可能長(zhǎng)這樣:
pragma solidity ^0.8.0;
contract Proxy {
address public target;
constructor(address _target) public {
target = _target;
}
function upgrade(address _target) public {
target = _target;
}
function vote() public {
require(msg.sender == msg.sender, "You must authenticate before voting.");
(bool success, bytes memory data) = target.delegatecall(abi.encodeWithSignature("vote()"));
}
}
然后,你可以部署代理合約,并告訴代理合約管理初始版本的目標(biāo)合約:
pragma solidity ^0.8.0;
contract VoteV1 {
uint256 public voteCount;
function vote() public {
voteCount += 1;
}
}
當(dāng)你需要升級(jí)智能合約時(shí),你可以編寫一個(gè)新版本的目標(biāo)合約:
pragma solidity ^0.8.0;
contract VoteV2 {
uint256 public voteCount;
function vote() public {
require(msg.sender == msg.sender, "You must authenticate before voting.");
voteCount += 1;
}
}
然后,你可以通過(guò)調(diào)用代理合約的 upgrade 函數(shù)來(lái)更新目標(biāo)合約的地址:
proxy.upgrade(address(VoteV2));
現(xiàn)在,所有對(duì)代理合約的請(qǐng)求都將被轉(zhuǎn)發(fā)到升級(jí)版本的智能合約,并且投票者必須通過(guò)身份驗(yàn)證才能投票。
這種方法可以保證合約的狀態(tài)不會(huì)丟失,因?yàn)樗袑?duì)原始合約的數(shù)據(jù)的引用仍然有效。此外,這種方法允許你在不影響現(xiàn)有合約的狀態(tài)的情況下對(duì)合約進(jìn)行升級(jí),并且每個(gè)版本都可以保證原子性。