如何部署和使用可升级的智能合约

在这篇博客中,我们将学习开发可升级智能合约背后的基本设计原则。最后,你会更清楚为什么要升级智能合约,如何升级智能合约,以及升级时需要考虑的问题。本文章主要关注以太坊和基于 EVM 的智能合约。

为了配合学习文章内容,你应该对区块链的工作原理有初步的了解,尤其是以太坊区块链。本文后面有一个简短的代码演示,因此你最好拥有一些编程经验,对 Solidity 及其编译方式、[智能合约是什么](https://chain.link/education/smart-contracts#:~:text=A smart contract is a,certain predefined conditions are satisfied.)以及部署方式有一些基本了解,以及如何使用像是 Metamask 和 Hardhat 这些工具。

什么是可升级智能合约?

数据的不可篡改性是区块链技术的核心原则之一。存储在以太坊区块链上的数据,包括部署到它的智能合约,也是不可变的。

在我们深入了解如何升级智能合约的细节之前,让我们先明确为什么我们需要升级智能合约。

主要原因是:

  • 修复 bug。
  • 改进功能。
  • 删掉没用的或添加需要的函数。
  • 优化代码以节省更多的 gas。
  • 响应技术、市场或社会的变化。
  • 避免将用户迁移到新版本的成本。

如果有足够的时间,大多数东西都需要一些维护工作。但是存储在区块链上的数据是不可变的。那么智能合约如何升级呢?

简单的说,智能合约本身无法更改——一旦部署到区块链,它们就是不可变的。但是 dApp 在设计模式上,可以有一个或多个智能合约一起运行,其中一些智能合约可以作为“后端”。这样的话,我们可以升级这些智能合约之间的交互模式。在这里,升级智能合约并不意味着修改已部署的智能合约的代码,而是将其中一个智能合约换成另一个。我们这样做的方式(在大多数情况下)可以让终端用户不必改变他们与 dApp 的交互方式。

所以真正升级智能合约是一个新智能合约替换旧智能合约的过程。当新的智能合约被使用后,旧的智能合约就会被“遗弃”在链上,因为旧的合约是不可变的。

如何升级合约?

智能合约通常使用“代理模式”进行升级,“代理模式”是一种软件架构模式。可以参考这个系统设计入门第 5 节了解更多“代理模式”的细节,但是长话短说,代理可以认为是一个大软件系统中的一个软件,它代表系统的一部分。在传统的 Web2 框架中,代理位于客户端应用程序和服务器应用程序之间。其中正向代理是客户端应用程序,而反向代理是服务器应用程序。

在智能合约的架构中,代理更像是一个反向代理,代表一个智能合约。它是一种中间件,可将前端接受的请求发送给系统后端对应的智能合约。作为智能合约,代理有自己的“稳定”(即不变)的以太坊合约地址。因此,你可以把系统中的旧的智能合约替换为新部署的智能合约。dApp 的最终用户直接与代理交互,并且仅通过代理间接与其他智能合约交互。

所以,在智能合约开发中,代理模式是通过以下两个部分来实现的:

  1. 代理智能合约
  2. 执行合约,也称为逻辑合约或实现合约(implementation contract)。 在这篇文章中,我们将以上部分分别称为代理合约和逻辑合约。

代理模式有三种常见的变体,我们将在下面讨论。

简单代理模式

简单代理模式的架构如下

file

让我们更深入地了解它是如何工作的。

在 EVM 中,有一种叫做“execution context”的东西,你可以将其视为执行代码的所需要的空间。

代理合约有自己的 execution context,所有其他智能合约也是如此。代理合约也有自己的存储空间,数据连同自己的 ETH 余额永久存储在区块链上。智能合约相关的的数据和余额一起称为其“状态”,而状态是其 execution context 的一部分。

代理合约使用存储变量来跟踪构成 dApp 的其他智能合约的地址。这就是它可以重定向交易并调用相关智能合约的方式。

但是有一个技巧可以用来将消息调用传递给正确的合约。代理合约不只是对逻辑合约进行常规函数调用;而是使用 Delegatecall。 Delegatecall 类似于常规函数调用,不同之处在于目标地址处的代码是在调用合约的 context 中执行的。如果逻辑合约的代码更改了存储变量,这些更改将反映在代理合约的存储变量中——即在代理合约的状态中。

那么 delegatecall 逻辑在代理合约中的什么位置呢?答案是代理合约的 fallback 函数。当代理合约收到自身无法处理的函数调用时,将调用代理合约的 fallback 函数来处理该函数调用。代理合约在其 fallback 函数中使用自定义逻辑将调用发送到逻辑合约。

将此原则应用于代理和逻辑合约,delegatecall 将调用逻辑合约的代码,但该代码在代理合约的 execution context 中运行。这意味着逻辑合约中的代码有权更改代理合约中的状态——它可以更改存储在代理合约中的状态变量和其他数据。这有效地将应用程序的状态与执行的代码分离。代理合约控制 dApp 的所有状态,也就意味着可以在不丢失 dApp 状态的情况下更改逻辑。

现在 dApp 状态和应用程序逻辑就可以在 EVM 中解耦了,我们可以通过更改逻辑合约并将新地址提供给代理来升级 dApp。但 dApp 的状态不受此升级的影响。

使用代理时,我们需要注意两个常见问题。

一个问题是存储冲突;另一种是代理选择器冲突(proxy selector clashing)。你可以阅读有关存储冲突的链接文章以了解更多信息,但现在我们将重点关注选择器冲突,因为它们是我们将要检查的代理模式的重要原因。

正如我们之前看到的,代理将所有函数调用委托给逻辑合约。但是,代理合约本身也具有函数,这些函数是它们内部的并且是它们运行所必需的。例如,代理合约需要像 upgradeTo(address newAdd) 这样的函数来升级到

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、玩过EOS的都知道,EOS本身更新迭代非常之快,所以有些知识点可能与最新版有所出入,希望小伙伴理解!此文档适用于EOS-v1.0.5以上版本和v1.1.x版本,目前的v1.2.x可能会有极少部分出入,比如eosiocpp工具看更新说明再不用安装的状态下就能使用,目前还未测试。有兴趣的小伙伴可以留言交流。 2、当前文档目录结构介绍: #思考研究问题 1、如何保证EOS中发布的智能合约不被随意篡改? #玩转EOS智能合约代码 #玩转客户端cleos 1、先玩转与智能合约相关的操作 #使用eosiocpp工具编译智能合约生成abi文件和wast文件 #编译合约(无法通过) #安装build/programs下工具 #重新编译合约 #部署合约到账户 #购买RAM #测试调用部署的合约 #更新\升级已经部署过的智能合约(相对空的合约) #更新添加新的函数接口(action)合约 #有关require_auth的合约测试 2、玩转智能合约与数据库相关操作 #参考资料 #持久化API (Multi-Index) 1、一般来讲,对数据库的操作无外乎增删改查 2、表结构示例详解 3、Multi_index定义,建立数据表 4、实例化multi_index 5、操作数据,增删改查 #玩转table表 1、Table表producers 2、Table表global 3、Table表voters 4、Table表rammarket (获取RAM实时价格) 5、Table表refunds (查看账户退款信息) 6、Table表namebids (罗列参与竞拍的账户信息) 3、启动nodeos节点出现脏数据 4、查看账户抵押资产,抵押token,赎回token #查看账户余额(可用余额) #查看SYS货币信息,eosio.token是经营货币的合约 #查看公钥对应账户 #查看子账户(控制账户) #查看账户信息 #查看账户抵押信息 #钱不够那就转账,随便耍 #get transaction无结果了解一下 #卖出RAM(卖给系统账户eosio.ram),字节bytes #抵押token获取CPU和net资源 #赎回抵押token,默认三天后到账,执行后可查看账户状态

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值