---
title: "升級智能合約"
description: "以太坊智能合約升級模式概述"
lang: zh-tw
---

以太坊上的智能合約是在以太坊虛擬機 (EVM) 中執行的自動執行程式。這些程式在設計上是不可變的，這可以防止在合約部署後對業務邏輯進行任何更新。

雖然不可竄改性對於智能合約的無須信任性、去中心化和安全性是必要的，但在某些情況下它可能是一個缺點。例如，不可變的程式碼可能使開發人員無法修復存在漏洞的合約。

然而，隨著對改進智能合約的研究不斷深入，引入了幾種升級模式。這些升級模式使開發人員能夠透過將業務邏輯放置在不同的合約中來升級智能合約（同時保留不可竄改性）。

## 先決條件 {#prerequisites}

你應該對[智能合約](/developers/docs/smart-contracts/)、[智能合約剖析](/developers/docs/smart-contracts/anatomy/)以及[以太坊虛擬機 (EVM)](/developers/docs/evm/)有充分的了解。本指南還假設讀者已經掌握了智能合約的程式設計。

## 什麼是智能合約升級？ {#what-is-a-smart-contract-upgrade}

智能合約升級涉及在保留合約狀態的同時更改智能合約的業務邏輯。必須澄清的是，可升級性和可變性並不相同，尤其是在智能合約的背景下。

你仍然無法更改部署到以太坊網路上某個地址的程式。但是，你可以更改使用者與智能合約互動時執行的程式碼。

這可以透過以下方法完成：

1. 建立智能合約的多個版本，並將狀態（即資料）從舊合約遷移到合約的新實例。

2. 建立獨立的合約來儲存業務邏輯和狀態。

3. 使用代理模式將函式呼叫從不可變的代理合約委託給可修改的邏輯合約。

4. 建立一個不可變的主合約，該合約與靈活的衛星合約介接並依賴它們來執行特定功能。

5. 使用鑽石模式將函式呼叫從代理合約委託給邏輯合約。

### 升級機制 #1：合約遷移 {#contract-migration}

合約遷移基於版本控制——即建立和管理同一軟體的獨特狀態的概念。合約遷移涉及部署現有智能合約的新實例，並將儲存和餘額轉移到新合約。

新部署的合約將具有空的儲存空間，允許你從舊合約中恢復資料並將其寫入新的實作中。之後，你需要更新所有與舊合約互動的合約，以反映新的地址。

合約遷移的最後一步是說服使用者切換使用新合約。新合約版本將保留使用者餘額和地址，從而保留了不可竄改性。如果它是基於代幣的合約，你還需要聯絡交易所放棄舊合約並使用新合約。

合約遷移是一種相對直接且安全的措施，可以在不破壞使用者互動的情況下升級智能合約。然而，手動將使用者儲存和餘額遷移到新合約非常耗時，並且可能會產生高昂的燃料 (gas) 成本。

[更多關於合約遷移的資訊。](https://blog.trailofbits.com/2018/10/29/how-contract-migration-works/)

### 升級機制 #2：資料分離 {#data-separation}

升級智能合約的另一種方法是將業務邏輯和資料儲存分離到獨立的合約中。這意味著使用者與邏輯合約互動，而資料則儲存在儲存合約中。

邏輯合約包含使用者與應用程式互動時執行的程式碼。它還保存儲存合約的地址，並與其互動以獲取和設定資料。

同時，儲存合約保存與智能合約相關的狀態，例如使用者餘額和地址。請注意，儲存合約由邏輯合約擁有，並在部署時配置了後者的地址。這可以防止未經授權的合約呼叫儲存合約或更新其資料。

預設情況下，儲存合約是不可變的——但你可以將其指向的邏輯合約替換為新的實作。這將更改在 EVM 中執行的程式碼，同時保持儲存和餘額完好無損。

使用此升級方法需要更新儲存合約中的邏輯合約地址。基於前面解釋的原因，你還必須使用儲存合約的地址來配置新的邏輯合約。

與合約遷移相比，資料分離模式可以說更容易實作。然而，你必須管理多個合約並實作複雜的授權方案，以保護智能合約免受惡意升級。

### 升級機制 #3：代理模式 {#proxy-patterns}

代理模式也使用資料分離將業務邏輯和資料保存在獨立的合約中。然而，在代理模式中，儲存合約（稱為代理）在程式碼執行期間呼叫邏輯合約。這與資料分離方法相反，在資料分離方法中，邏輯合約呼叫儲存合約。

以下是代理模式中發生的情況：

1. 使用者與代理合約互動，代理合約儲存資料，但不包含業務邏輯。

2. 代理合約儲存邏輯合約的地址，並使用 `delegatecall` 函式將所有函式呼叫委託給邏輯合約（包含業務邏輯）。

3. 呼叫轉發到邏輯合約後，將檢索從邏輯合約返回的資料並將其返回給使用者。

使用代理模式需要了解 **delegatecall** 函式。基本上，`delegatecall` 是一個操作碼，允許一個合約呼叫另一個合約，而實際的程式碼執行發生在呼叫合約的上下文中。在代理模式中使用 `delegatecall` 的一個含義是，代理合約讀取和寫入其儲存，並執行儲存在邏輯合約中的邏輯，就像呼叫內部函式一樣。

來自 [Solidity 文件](https://docs.soliditylang.org/en/latest/introduction-to-smart-contracts.html#delegatecall-callcode-and-libraries)：

> _存在一種名為 **delegatecall** 的特殊訊息呼叫變體，它與訊息呼叫相同，不同之處在於目標地址的程式碼是在呼叫合約的上下文（即地址）中執行的，並且 `msg.sender` 和 `msg.value` 不會改變它們的值。_ _這意味著合約可以在執行時動態地從不同的地址載入程式碼。儲存、當前地址和餘額仍然引用呼叫合約，只有程式碼是從被呼叫的地址獲取的。_

代理合約知道在使用者呼叫函式時呼叫 `delegatecall`，因為它內建了一個 `fallback` 函式。在 Solidity 程式設計中，當函式呼叫與合約中指定的函式不匹配時，將執行[回退函式](https://docs.soliditylang.org/en/latest/contracts.html#fallback-function)。

要使代理模式發揮作用，需要編寫一個自訂的回退函式，該函式指定代理合約應如何處理它不支援的函式呼叫。在這種情況下，代理的回退函式被編程為啟動 delegatecall 並將使用者的請求重新路由到當前的邏輯合約實作。

代理合約預設是不可變的，但可以建立具有更新業務邏輯的新邏輯合約。執行升級就是更改代理合約中引用的邏輯合約的地址。

透過將代理合約指向新的邏輯合約，當使用者呼叫代理合約函式時執行的程式碼就會改變。這使我們能夠升級合約的邏輯，而無需讓使用者與新合約互動。

代理模式是升級智能合約的一種流行方法，因為它們消除了與合約遷移相關的困難。然而，代理模式使用起來更複雜，如果使用不當，可能會引入嚴重的缺陷，例如[函式選擇器衝突](https://medium.com/nomic-foundation-blog/malicious-backdoors-in-ethereum-proxies-62629adf3357)。

[更多關於代理模式的資訊](https://blog.openzeppelin.com/proxy-patterns/)。

### 升級機制 #4：策略模式 {#strategy-pattern}

這種技術受到[策略模式](https://en.wikipedia.org/wiki/Strategy_pattern)的影響，該模式鼓勵建立與其他程式介接以實作特定功能的軟體程式。將策略模式應用於以太坊開發意味著建立一個呼叫其他合約函式的智能合約。

在這種情況下，主合約包含核心業務邏輯，但與其他智能合約（「衛星合約」）介接以執行某些功能。該主合約還儲存每個衛星合約的地址，並可以在衛星合約的不同實作之間切換。

你可以建立一個新的衛星合約，並使用新地址配置主合約。這允許你更改智能合約的_策略_（即實作新邏輯）。

雖然與前面討論的代理模式相似，但策略模式有所不同，因為使用者互動的主合約包含業務邏輯。使用這種模式使你有機會對智能合約進行有限的更改，而不會影響核心基礎設施。

主要缺點是這種模式主要用於推出次要升級。此外，如果主合約遭到破壞（例如，透過駭客攻擊），你將無法使用此升級方法。

### 升級機制 #5：鑽石模式 {#diamond-pattern}

鑽石模式可以被認為是代理模式的改進。鑽石模式與代理模式不同，因為鑽石代理合約可以將函式呼叫委託給多個邏輯合約。

鑽石模式中的邏輯合約被稱為_切面 (facets)_。為了使鑽石模式發揮作用，你需要在代理合約中建立一個映射，將[函式選擇器](https://docs.soliditylang.org/en/latest/abi-spec.html#function-selector)映射到不同的切面地址。

當使用者進行函式呼叫時，代理合約會檢查映射以找到負責執行該函式的切面。然後它呼叫 `delegatecall`（使用回退函式）並將呼叫重定向到適當的邏輯合約。

鑽石升級模式相對於傳統的代理升級模式有一些優勢：

1. 它允許你升級合約的一小部分，而無需更改所有程式碼。使用代理模式進行升級需要建立一個全新的邏輯合約，即使是次要升級也是如此。

2. 所有智能合約（包括代理模式中使用的邏輯合約）都有 24KB 的大小限制，這可能是一個限制——特別是對於需要更多功能的複雜合約。鑽石模式透過將功能拆分到多個邏輯合約中，輕鬆解決了這個問題。

3. 代理模式對存取控制採用包羅萬象的方法。有權存取升級功能的實體可以更改_整個_合約。但是鑽石模式支援模組化權限方法，你可以限制實體只能升級智能合約中的某些功能。

[更多關於鑽石模式的資訊](https://eip2535diamonds.substack.com/p/introduction-to-the-diamond-standard?s=w)。

## 升級智能合約的優缺點 {#pros-and-cons-of-upgrading-smart-contracts}

| 優點                                                                                                           | 缺點                                                                                                                                                    |
| -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 智能合約升級可以更容易地修復在部署後階段發現的漏洞。    | 升級智能合約否定了程式碼不可竄改性的概念，這對去中心化和安全性有影響。                              |
| 開發人員可以使用邏輯升級為去中心化應用程式 (dapp) 添加新功能。                           | 使用者必須信任開發人員不會隨意修改智能合約。                                                                                  |
| 智能合約升級可以提高終端使用者的安全性，因為可以快速修復錯誤。                      | 將升級功能編程到智能合約中會增加另一層複雜性，並增加出現嚴重缺陷的可能性。                |
| 合約升級為開發人員提供了更多空間來試驗不同的功能，並隨著時間的推移改進 dapp。 | 升級智能合約的機會可能會鼓勵開發人員更快地啟動專案，而不在開發階段進行盡職調查。 |
|                                                                                                                | 智能合約中不安全的存取控制或中心化會使惡意行為者更容易執行未經授權的升級。                  |

## 升級智能合約的注意事項 {#considerations-for-upgrading-smart-contracts}

1. 使用安全的存取控制/授權機制來防止未經授權的智能合約升級，特別是在使用代理模式、策略模式或資料分離時。一個例子是限制對升級功能的存取，使得只有合約的擁有者才能呼叫它。

2. 升級智能合約是一項複雜的活動，需要高度的謹慎以防止引入漏洞。

3. 透過將實作升級的過程去中心化來減少信任假設。可能的策略包括使用[多重簽名錢包合約](/developers/docs/smart-contracts/#multisig)來控制升級，或要求 [DAO 成員](/dao/)投票批准升級。

4. 注意升級合約所涉及的成本。例如，在合約遷移期間將狀態（例如使用者餘額）從舊合約複製到新合約可能需要多筆交易，這意味著更多的燃料費用。

5. 考慮實作**時間鎖 (timelocks)** 來保護使用者。時間鎖是指對系統更改強制執行的延遲。時間鎖可以與多重簽名治理系統結合使用來控制升級：如果提議的操作達到所需的批准閾值，它不會執行，直到預先定義的延遲時間過去。

時間鎖讓使用者在不同意提議的更改（例如，邏輯升級或新的費用方案）時，有一些時間退出系統。如果沒有時間鎖，使用者需要信任開發人員不會在沒有事先通知的情況下在智能合約中實作任意更改。這裡的缺點是時間鎖限制了快速修補漏洞的能力。

## 資源 {#resources}

**歐本齊柏林 (OpenZeppelin) 升級外掛程式 - _一套用於部署和保護可升級智能合約的工具。_**

- [GitHub](https://github.com/OpenZeppelin/openzeppelin-upgrades)
- [文件](https://docs.openzeppelin.com/upgrades)

## 教學 {#tutorials}

- [升級你的智能合約 | YouTube 教學](https://www.youtube.com/watch?v=bdXJmWajZRY)，作者：Patrick Collins
- [以太坊智能合約遷移教學](https://medium.com/coinmonks/ethereum-smart-contract-migration-13f6f12539bd)，作者：Austin Griffith
- [使用 UUPS 代理模式升級智能合約](https://blog.logrocket.com/author/praneshas/)，作者：Pranesh A.S
- [Web3 教學：使用歐本齊柏林 (OpenZeppelin) 編寫可升級智能合約（代理）](https://dev.to/yakult/tutorial-write-upgradeable-smart-contract-proxy-contract-with-openzeppelin-1916)，作者：fangjun.eth

## 延伸閱讀 {#further-reading}

- [智能合約升級的狀態](https://blog.openzeppelin.com/the-state-of-smart-contract-upgrades/)，作者：Santiago Palladino
- [升級 Solidity 智能合約的多種方法](https://cryptomarketpool.com/multiple-ways-to-upgrade-a-solidity-smart-contract/) - Crypto Market Pool 部落格
- [學習：升級智能合約](https://docs.openzeppelin.com/learn/upgrading-smart-contracts) - 歐本齊柏林 (OpenZeppelin) 文件
- [Solidity 合約可升級性的代理模式：透明代理與 UUPS 代理](https://mirror.xyz/0xB38709B8198d147cc9Ff9C133838a044d78B064B/M7oTptQkBGXxox-tk9VJjL66E1V8BUF0GF79MMK4YG0)，作者：Naveen Sahu
- [鑽石升級如何運作](https://dev.to/mudgen/how-diamond-upgrades-work-417j)，作者：Nick Mudge