# 深入理解合约升级(1) - 概括

By [xyyme.eth](https://paragraph.com/@xyyme) · 2022-04-14

---

这篇文章开始，我将用一个系列的文章详细介绍智能合约升级原理，尽量会以 Solidity 初学者的角度来探究，同时也能帮助自己更加巩固对这个知识点的了解。

### 了解合约升级

我们知道，区块链上的内容都是不可变的，一旦数据上链之后，那么便是不可修改的。智能合约也是一样，部署在链上之后，合约本身的代码便是不可修改的，如果部署之后发现了合约中有 bug，那就完全没办法，只能另外部署一份合约了。其实这样也是有好处的，因为如果一份合约没有问题的话，那么也就代表它能够一直正确运行，而没有人能够修改合约的运行逻辑，真正达到的 `Code is law` 的理念。

但是，作为项目开发而言，这样就不是很友好了。首先，如果代码中有 bug，无法修改，如果这个 bug 是关乎用户 token 转账等场景，可能会造成用户的资产永久锁死在合约中。其次，项目发展是一个长期的过程，不可能一开始就能把所有的功能都考虑到。如果后期想要添加功能，那么就只能更换合约，并且需要用户手动操作，将旧合约中的数据（资产）转移到新合约中，这样可能会造成用户的困扰。

那么我们自然想到，合约开发能不能也可以像传统互联网开发那样，有问题随时修改，并且对于用户是无感知的呢？这时就引入了我们要介绍的合约升级的概念。

### 合约如何升级

首先，我们来看传统的合约调用逻辑：

![](https://storage.googleapis.com/papyrus_images/cd7b64f9487beb70d301593195fa86ff2121194a9721b5a19316036145d20250.png)

用户最初与旧合约进行交互，如果更新了新的合约，那么用户需要更换交互地址，迁移数据。新旧合约分别保存了各自的数据，两者互不关联。那么如果我们想要做成前面说的无感知升级，该怎么操作呢？

我们知道，合约本身是不能更改的，那么我们考虑，能不能用一种代理人的方式，也就是说，我们去调用一个代理合约，代理合约将我们发送的请求，也就是函数调用，转发给实际执行逻辑的合约，当需要更换新合约的时候，只需要在代理合约转发请求时，将请求发送给新的合约地址就可以了。而用户对这一切是不知道的，因为用户自始至终都是与代理合约做交互。来看看一个简单的图示：

![](https://storage.googleapis.com/papyrus_images/6cf753ed9b8370cf106508064a413cc8e2a3be1501564ba291084365ae89c0c6.png)

如图中所示，我们在实际执行逻辑的合约前面加了一个代理合约，用户一直是与代理合约交互，开始时代理合约将请求转发给旧合约，当需要升级时，部署一个新的合约，同时代理合约会将请求转发给新合约，这样对于用户来说就是无感知的。

但是这里还有一个问题，我们前面说到，在传统合约模式中，用户是需要将数据从旧合约迁移到新合约中的，现在加了一个代理合约，请求是转发过去了，那么数据怎么办呢，用户的 token 不是还在旧合约中吗？此时，我们应该想到，其实代理合约不仅仅是起到转发请求的作用，而且承载了所有的合约数据，包括用户的 token 也都是存放在代理合约中，右边的逻辑合约也就仅仅是实现逻辑而已，不保存任何数据：

![](https://storage.googleapis.com/papyrus_images/ed3830487b6a3c3da475056839ea8a2a8770c5d05eb9a0208aed5edc525b742f.png)

这样一来，我们就能随意更换逻辑合约，而不用担心数据迁移问题。也就是说，我们已经做到了和传统互联网开发一样，能够对合约进行升级。这样对于用户体验和项目方维护来说都是一个很大的优点。

那么既然合约升级这么好，为什么不是所有的项目都采用可升级合约呢？前面我们说到，可升级与不可升级之间，各自都是有利有弊的，这取决于项目方的权衡。

对于可升级合约来说，好处是优化用户体验，利于项目方维护。而坏处就是项目方可以随时更改后面的逻辑合约作恶，将用户的 token 转走，这对于用户来说是无能为力的。（现在有很多项目的升级权限都是由多签管理，但是仍然存在风险）

相对应的，对于不可升级合约，一切都写在了代码中，真正实现了 `Code is law` 的理念，即使项目方自己也不能随意更改合约，操纵用户资产。例如 `Uniswap` 的合约都是不可升级的，用户在与其进行交互时，是可以放心将资产放在上面的。但是代价就是项目开发时要做到各种测试，包括项目审计也要做很多遍，因为一旦部署，就无法更改了。（这里并不是说使用了可升级合约就可以省去这些安全步骤，安全一定是合约开发的重中之重，只是说可升级合约即使发现了 bug，也可以后期修改）

综合而言，两者都有各自的优缺点，取决于项目方的考虑与权衡。但要注意的是，并不是说不可升级合约就一定是安全的项目方，而可升级的合约就一定是是不安全的项目方。项目方之间差距也很大，例如 [USDC](https://etherscan.io/address/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48#code) 就是可升级合约，但是 USDC 几乎可以说是不会作恶的。

### 总结

通过代理合约模式可以实现合约升级，对于用户是无感知的。同时合约升级也是有利有弊，需要针对具体场景判断选择哪种模式。

### 合约升级系列文章

1.  [深入理解合约升级(1) - 概括](https://mirror.xyz/xyyme.eth/RZscMYGkeGTY8z6ccHseY8HKu-ER3pX0mFYoWXRqXQ0)
    
2.  [深入理解合约升级(2) - Solidity 内存布局](https://mirror.xyz/xyyme.eth/5eu3_7f7275rqY-fNMUP5BKS8izV9Tshmv8Z5H9bsec)
    
3.  [深入理解合约升级(3) - call 与 delegatecall](https://mirror.xyz/xyyme.eth/0gmFpVZVlHhwb2YlmaSY8Dyv5r3Z24sKIks38cyQRFk)
    
4.  [深入理解合约升级(4) - 合约升级原理的代码实现](https://mirror.xyz/xyyme.eth/VSyU0JfmVrcqN-F28tX5mzYjxFFAosl8tDAQX3vB5Dg)
    
5.  [深入理解合约升级(5) - 部署一个可升级合约](https://mirror.xyz/xyyme.eth/kM9ld2u0D1BpHAfXTiaSPGPtDnOd6vrxJ5_tW4wZVBk)
    

### 关于我

欢迎[和我交流](https://linktr.ee/xyymeeth)

---

*Originally published on [xyyme.eth](https://paragraph.com/@xyyme/1)*
