OpenZeppelin 合約昇級插件 1/9

以太坊 ethereum andy 4年前 (2020-10-05) 1444次浏览 已收录 0个评论 扫描二维码
文章目录[隐藏]

OpenZeppelin 合約昇級插件 1/9

在寫了幾個合約之後,對於同一個合約的昇級問題,一直覺得不是很好管理。
Ethereum 的智能合約,創建了之後無法修改原合約,但是可以刪除。所以合約的更新,一般順序就是部署新的合約,然後把所有關的應用地址更改為新合約的地址,最後再把舊合約刪除。當然這中間會包括新舊合約內資產的轉移之類的相關操作。
這裡產生的問題,就是在更改相關應用的合約地址時,不可遺漏。甚至如果有合約調用之類的操作,那整個更新的動作將會變得十分繁複,並且容易出錯。
因此,我選用了 OpenZeppelin 的合約昇級插件來學習,這個系列文章按照官網的文檔順序來寫,會加上我自己實作的結果及心得,所以這不是原文的翻譯,不可以做為原文的替代品。

20201109 補充

我在本系列文章,把 migration 、migrate 翻譯為”部署”的原因有兩個,第一個是比較符合行為的意義,一般我們說部署是指,把編譯好的程式放到生產或測試環境之中,也就是把各種檔案放到它應該去的地方。可是在智能合約的開發,這是分為兩個步驟,編譯好之後再使用 0交易發布到鏈上。另一個原因是已經有其他文章將 migrate 翻譯為部署。綜合考量這兩個因素,再加上 migrate 動作,與其”遷移”不如”部署”。在最後一章,因為 migrate 跟 deploy 出現次數很多,因此才分開各以原文書寫。

 

合約昇級插件

這個插件可以把昇級合約這件事加到你現有的工作流裡面。這個插件讓 Buidler 和 Truffle 兩個整合開發環境可以在以太坊上部署及管理可昇級的合約。

本插件的目標是以下四項

  • 部署可昇級的合約
  • 昇級已部署的合約
  • 管理代理管理員(proxy admin) 權限
  • 容易測試

總覽

安裝方式

Buidler 的安裝方式

$ npm install --save-dev @openzeppelin/buidler-upgrades @nomiclabs/buidler-ethers ethers
以上命令安裝了本插件及必要的依賴程式庫

Truffle 安裝

$ npm install --save-dev @openzeppelin/truffle-upgrades

用法

詳細的用法請各自參考 Truffle 及 Buidler ,以下是簡單的用法程式片段。

Buidler的用法

Buidler的用戶可以寫腳本來部署或昇級合約,也可以管理代理管理員權限。

const { ethers, upgrades } = require("@nomiclabs/buidler");

async function main() {
// Deploying
const Box = await ethers.getContractFactory("Box");
const instance = await upgrades.deployProxy(Box, [42]);
await instance.deployed();

// Upgrading
const BoxV2 = await ethers.getContractFactory("BoxV2");
const upgraded = await upgrades.upgradeProxy(instance.address, BoxV2);
}

main();

Truffle 用法

Truffle 的用戶,可以寫稱為 migrations 的設定檔,來使用插件。可以部署,昇級,管理代理管理員權限。

const { deployProxy, upgradeProxy } = require('@openzeppelin/truffle-upgrades');

const Box = artifacts.require('Box');
const BoxV2 = artifacts.require('BoxV2');

module.exports = async function (deployer) {
  const instance = await deployProxy(Box, [42], { deployer });
  const upgraded = await upgradeProxy(instance.address, BoxV2, { deployer });
}

測試用法

無論用的是 Buidler 或 Truffle ,都可以用這個插件來測試,以確定在預期中運作。

it('works before and after upgrading', async function () {
  const instance = await upgrades.deployProxy(Box, [42]);
  assert.strictEqual(await instance.retrieve(), 42);

  await upgrades.upgradeProxy(instance.address, BoxV2);
  assert.strictEqual(await instance.retrieve(), 42);
});

插件是如何運作的

插件提供兩個主要的函數,deployProxyupgradeProxy 。負責管理合約的可昇級部署。

在調用 deployProxy 函數時,完成以下四件事

  1. 驗証合約的實作是可以安全昇級的
  2. 為你的專案部署一個代理管理員(proxy admin) 合約
  3. 部署功能實作合約
  4. 建立及初始化代理合約

在調用 upgradeProxy 函數時,完成以下三件事

  1. 驗証新的功能實作合約是不是可安全昇級,是不是跟前一版本相容
  2. 檢查功能實作合約的 bytecode 是不是跟前一版本相同,不相同才部署
  3. 昇級代理合約,使用新的功能實作合約

插件會持續的追蹤所有在專案根目錄底下的 .openzeppelin 目錄下的所有功能實作合約及代理管理員。在目錄裡面一個每個網路名稱會配一個檔案,建議針對所有的網路都做版本管理。

管理所有權

所有的代理都會定義管理員地址,只有管理員有權限更新。預設是代理管理員合約,可以調用 admin.changeAdminForProxy 函數來更改代理管理員。記得代理管理員只能更新代理合約,不能和功能實作合約交互。
代理管理員合約也定義了擁有者地址,這個地址有操作權限。預設這個地址是部署時的外部帳戶。可以調用 admin.transferProxyAdminOwnership 函數來修改代理管理員的擁有者地址。注意這個會改變更新任何代理合約的權力,要小心使用。
修改了更新的權限的地址,還是可以用本地的設定來驗証和部署功能實作合約。插件裡的 prepareUpgrade 函數可以驗証新的功能實作合約是不是可以安全昇級,和之前的合約是不是相容。然後用本地的以太坊帳戶部署。最後用 admin 地址來執行更新。

在下一篇中我會先說明文中的特定名詞,如代理管理員,可以安全昇級的合約,功能實作合約

參考

https://docs.openzeppelin.com/upgrades-plugins/1.x/
https://buidler.dev/
https://www.trufflesuite.com/truffle


神隊友學長Andy , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:OpenZeppelin 合約昇級插件 1/9
喜欢 (0)
[[email protected]]
分享 (0)
andy
关于作者:
中年大叔,打拼 like young students.
发表我的评论
取消评论
表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址