开发人员最难掌握的Web3.0概念
共 4231字,需浏览 9分钟
· 2022-01-15
这是大多数新的 Web 3.0 开发人员难以理解的事情:当您发布代码时,以后无法对其进行修补和更新。这与我们都知道和喜爱的迭代开发方法有很大的不同——我们将开发分解成更小的部分,并通过多次迭代来构建它。通过逐一添加功能,我们可以随着时间的推移改进应用功能——同时扩大用户群。在 Web 3.0 中,这是无法做到的。
迭代开发让我们分阶段构建
稍后我们将讨论 Web 3.0 的瀑布方法。但首先,需要了解迭代开发的入门知识。以这种方式构建应用程序有几个优点:
1) 及早发现错误
通过分阶段构建软件,我们可以逐段构建、测试和交付代码。这让我们可以在早期阶段发现错误并在进行时修复它们,避免下游后果,例如影响整个应用程序的一些小错误。
2)更快的用户反馈
由于我们以迭代方式发布应用程序,迭代开发让我们能够快速、循环地获得反馈。这不仅让我们能够进行必要的错误修复,而且还帮助我们根据用户的实时反馈制定未来的路线图。
3) 减少时间计划
迭代开发为我们节省了编写复杂文档的时间,因此我们可以花更多的时间构建和测试,而减少编写和理论化的时间。
但这在 Web3.0中发生了变化
当然,区块链改变了一切——包括迭代开发的可能性。大多数新的软件开发人员得知这一点后都会感到震惊,但是一旦您掌握了智能合约的工作原理,就说得通了。
我们以以太坊区块链为例。(如果您需要入门,请阅读本文 https://www.preethikasireddy.com/post/how-does-ethereum-work-anyway。)
以太坊是一个全球可访问的状态机,只能通过共识进行更新。作为一个不可变的状态机,我们可以向它写入状态(即数据),但是我们不能更新状态。这意味着:
这有一个很好的理由:智能合约让我们在参与者之间创建一个牢不可破的合约。但这也意味着我们永远受合同约束。因此,错误修复和改进是不可能的。
如果您来自 Web 2.0,您可能想知道为什么有人会开发无法更新的东西。甚至想想都觉得害怕。这就是为什么许多加密项目需要数月甚至数年才能将其应用程序部署到区块链上的原因——智能合约中的任何错误或漏洞都可能造成数百万美元的损失。
此类黑客的例子数不胜数,您可以在此处: https://medium.com/firmonetwork/3-famous-smart-contract-hacks-you-should-know-dffa6b934750 阅读有关这些内容的信息 https://consensys.github.io/smart-contract-best-practices/known_attacks/ ……以及通过简单的 Google 搜索即可找到更多内容。
如果我们一定需要进行更新怎么办呢?
这就引出了我们的下一个问题:如果我们绝对需要进行更新怎么办?
假设开发人员犯了一个价值数百万美元的错误;有人破解了他们的智能合约并榨取了大量资金。当然,必须采取措施阻止其他用户使用这些智能合约——但这是一个非常乏味的过程。
以下是这种情况下通常会发生的情况:
第一步
您发现该漏洞的 通过暂停智能联系人,您可以做两件事:首先,明确表示用户不应使用它们,其次,防止攻击者利用不知道该漏洞的用户。
第二步
接下来,您需要恢复数据,以便迁移到新的智能合约。请记住,在 Web 3.0 中,您的智能合约存储应用程序的逻辑和数据(有关 Web 3.0 架构和智能合约的入门,在随后的文章中会进行介绍)。当您部署具有更新逻辑(修复您的漏洞)的新智能合约时,您需要恢复该数据;否则,一切都会被抹去。您将恢复的数据示例包括:
第三步
接下来,您使用恢复的数据编写并启动新合同。如果您的数据很少,则可以在一次事务中完成此过程。但是,如果您有大量数据,则必须将其分解为许多较小的事务。回想一下,将数据写入以太坊区块链需要花钱,而这笔钱是用“Gas”支付的。以太坊对每笔交易都有一个“GasLimit”;如果交易的 gas 成本超过此限制,矿工将不会将其包含在区块中。
第四步
部署新合约意味着合约地址发生了变化。因此,您现在需要使用新地址更新与旧合约交互的所有合约。此外,您需要让您的用户知道这是他们应该使用的新合同。这需要大量的社会协调,并不总是那么简单,但很有可能。
这种乏味的方法的好处是我们不会牺牲不变性,这是智能合约的基本属性。但是,不可否认迁移数据和说服用户迁移的乏味。这就是为什么任何将智能合约部署到区块链上的人都必须在部署之前制定迁移计划的原因——这样,如果他们发现了一个漏洞,他们就有了一个备份计划。
构建可升级的智能合约:一种后门方法
虽然我们刚刚讨论的手动方法有效,但它仍然不理想。有很多例子表明价值数百万美元的以太币被盗或被黑客入侵,如果我们能够更新智能合约,这些以太币本可以被挽救。拥有升级合约的能力不仅对迭代开发有用,而且对修复可能会消耗人们储蓄的严重错误也很有用。
这就是以太坊社区(特别是OpenZeppelin https://openzeppelin.com/)提出“可升级智能合约”概念的原因。
这个概念很简单。我们有一个“代理合约”和一个“逻辑合约”。代理合约委托到逻辑契约。您的最终用户始终与您的代理合同进行交互,该合同存储您的所有应用程序数据。但是,该方法的实际逻辑存储在逻辑合约中。
当用户与代理合约交互时,它会将这些交易转发到逻辑合约并从函数调用中检索返回数据。然后将数据转发回调用者。
因此,当您需要更新逻辑时,您只需更新逻辑合约并重新部署它。
请注意,这两个智能合约仍然是不可变的。您只是换出代理合约调用的逻辑合约。由于用户只与代理合约进行交互,因此您无需精心制作歌曲和舞蹈来让每个人切换到新合约。
代理合同如何在幕后运作
代理合约只定义了一个方法:回退函数(https://solidity.readthedocs.io/en/v0.6.12/contracts.html#fallback-function)。如果没有其他函数与给定的函数签名匹配,则在调用合约时执行此操作。因此,当代理合约被调用时,由于没有定义其他方法,所以调用了回退函数。回退函数具有告诉合约将调用转发到逻辑合约的逻辑。它可以做到这一点,而无需特别了解逻辑合约的接口。
如果您不熟悉 Solidity,您可能想知道智能合约如何将函数调用转发到另一个合约。Solidity 有一个叫做“ delegatecall ”的概念,它类似于合约调用,只是有一点点不同。
假设我们有执行的合约 A委托调用合约 B,然后合约 B 的代码与合约 A 的storage、msg.sender和msg.value 一起执行。
我们将使用Solidity by Example网站中提供的示例来演示 delegatecall 的工作原理。
在这个例子中,合约 A 使用委托调用来调用合约 B 上的setVars,只是我们使用合约 A 的存储而不是合约 B 的存储中的数据来执行调用。换句话说,存储、当前地址和余额仍然参考调用合约(即合约A),并且仅从被调用地址(即合约B)中取出代码。
因此,在我们的可升级智能合约方案中,当用户调用代理合约时,会调用回退函数,然后使用代理合约中的数据“委托”对逻辑合约中定义的方法的调用。
有关详细示例,我建议您阅读OpenZeplin 关于可升级智能合约的文档的这一页(https://docs.openzeppelin.com/learn/upgrading-smart-contracts)。
请注意,用户或恶意行为者仍然可以直接向逻辑合约发送交易。但是,这不会构成威胁,因为逻辑契约状态的更改不会影响您的应用程序;您的应用程序将数据存储在代理合约而不是逻辑合约中。
可升级智能合约的优缺点
可升级的智能合约已经变得非常流行。然而,对于可升级合同是好事还是坏事,业内存在分歧。Trail of Bits 在这篇文章中(https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/)做得很好,概述了使用 delegatecall 进行可升级合约的风险,我将在下面进行总结。
假设用户调用代理合约,然后调用逻辑合约。逻辑合约执行函数并将数据写回代理合约。到现在为止还挺好。
这就是它变得棘手的地方: 当逻辑合约尝试写入代理合约时,它会在代理状态的范围内这样做。
让我们使用OpenZeppelin 文档中(https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies)提供的示例来说明为什么这可能是危险的。我们使用以下变量定义了代理和逻辑合约。
代理将逻辑合约的地址存储在第一个存储槽中。逻辑合约将“所有者”的地址存储在其第一个槽中。两个变量的大小均为 32 字节。如果逻辑合约被执行并写入“所有者”变量,它将在代理合约的上下文中执行。这意味着它会尝试写入代理合约的第一个存储槽。这将导致存储冲突。
OpenZeppelin 的可升级智能合约克服这个问题的方法是随机化代理合约存储槽。
这确保了逻辑合约写入代理合约上已被另一个变量使用的存储槽的可能性可以忽略不计。
这种随机化存储槽的方法被称为“非结构化存储”。虽然它有效,但它增加了智能合约的复杂性,因此为错误和严重错误留下了更多空间。它还要求开发人员了解以太坊 EVM 的内部结构以及存储的工作原理,这对于想要构建应用程序的人来说是一种不公平的期望。
结论
如果您是 Web 3.0 的新手或正在考虑学习 Web 3.0 开发,那么了解智能合约的不可变性质至关重要。这样,您就可以规划需要升级智能合约的场景。您是采用更乏味的传统方法还是使用 OpenZeppelin 的可升级智能合约方案,取决于您的用例——以及您愿意做出的权衡。但是,无论哪种方式,都要制定计划。