当人们试图区分 Web2 和 Web3 时,区分两者的一个关键价值是所有权的概念。
简而言之,您所创造的就是您所拥有的,并且可以从中获利。就像它应该的那样。仅此而已。事实上,由于区块链的不变性,当你以所有者的身份在 Web3 中创建第一个 NFT 时,就是你铸造第一个 NFT 的那一天。如果有的话,被保护的感觉是无价的。
说到这一点,这种所有权概念对于智能合约在可访问功能和允许状态更改方面同样重要。
那么,为什么您“拥有”您编写的智能合约很重要?
想一想:如果您拥有一辆自行车,您会犹豫保留所有权记录吗?以防万一有人偷了它并将其用于邪恶目的?当然不是。
这与您想要证明您对 NFT 或智能合约的所有权的原因完全相同。好吧,有人可能只是获得未经授权的访问并从中获利,对吧?
假设您与 Dunzo 合作并编写了这份智能合约,您可以在其中设置包裹价格加上运费以及是否由买方支付。
在理想的场景下,您可以将买家姓名、包裹总价和运费设置为一定数量,并将setPackageDelivered设置为true。当然,一旦您完成交付包裹。
但是,众所周知,任何事情都不会按计划进行。
现在,如果买方可以访问合同功能并能够将 packageDelivered 值重置为 false 或将 packageDeliveryPrice 值更改为较小的值,会怎样?他们不仅可以为产品支付更少的费用,而且可以完全不支付任何费用。
显然,除了 Dunzo 之外,没有其他人有权进行此类更改,这就是设置访问控制很重要的原因。
现在,让我们部署这个智能合约,看看入侵者更改状态变量中的值有多么容易。
由于可以访问 setPrice 和 setPackageDelivered 函数,任何人都可以做出可能导致 Dunzo 交付的财务损失的更改。
如果 Dunzo 将商品的原价设置为 5 ETH,客户现在可以将该值更改为 3 ETH。当然,由于客户也可以访问 setPackageDelivered 函数并将布尔值更改为 false,他可能会收到另一批相同的商品。因此,无论哪种情况,Dunzo 都将赔钱,而且可能直到为时已晚才意识到这一点。
例如,假设正在交付的产品价值 5 ETH,如下所示:
部署后,除了 Dunzo 之外,没有人能够修改合同条款。尽管如此,当我们在 Remix 中切换地址并将价格重置为 3 时,由于没有适当的保护,这是可能的。
我们甚至可以将 setPackageDelivered 状态从 true 更改为 false。即使包裹已经交付给客户。
如您所知,区分上述智能合约的所有者和其他用户非常重要。因此,让我们看一下 4 个修复程序,它们将为该智能合约设置适当的访问控制并确保其安全。
那么,在编写智能合约时如何区分所有者和其他用户呢?
显然,这是必要的,因为如果忽略可能会造成经济损失。
方法 #1:使用 require 语句
正如您在下面的代码中看到的,地址类型的新状态变量 owner 已与“require”语句一起添加。在构造函数中,所有者状态变量存储部署合约时使用的地址。如您所知,智能合约中的构造函数仅被调用一次,因此地址无法更改。
现在,当您使用较小的值和不同的地址调用 setPrice 函数时,交易将恢复到初始状态,就像下面的消息一样:
如您所见,合约提供的原因涉及我们添加到“require”语句中的错误消息。也就是说,除了合同的所有者——在这种情况下是 Dunzo——之外,没有人可以更改销售条款。
方法#2:使用函数修饰符
就像添加具有正确条件的“require”语句一样简单,修饰符是一个可以重复使用的代码块。这当然比为此类检查编写大量“要求”语句更有意义。
在之前共享的代码中,只有 setPrice 函数受“require”语句保护,但此处没有对 setPackageDelivered 函数进行任何操作。使用修饰符应该可以解决问题,如下面的 Solidity 代码所示:
现在,如果您尝试访问 setPrice 或 setPackageDelivered 函数,您将收到与之前相同的错误消息,如下所示:
方法#3:拥有
此修复要求您使用 OpenZeppelin 提供的 Ownable 智能合约。首先,您必须导入 Ownable 智能合约,然后将 onlyOwner 修饰符添加到您想要保护的函数中。因此,如下所示,setPrice 和 setPackageDelivered 函数都具有下面的 onlyOwner 修饰符。
现在,由于 dunzoDelivery 智能合约将使用 Ownable.sol 中的一些功能,因此也将“is Ownable”添加到合约名称中。
也就是说,在使用 Ownable 智能合约时可以访问另外两个功能:renounceOwnership 和 transferOwnership。虽然用于部署合约的帐户通常被认为是所有者,但可以使用这些功能进行更改。
除了查看所有者的地址和其他协议详细信息外,您还可以在下面看到使用的 renounceOwnership 和 transferOwnership 函数:
正如预期的那样,当您尝试使用另一个地址调用 setPrice 函数时,交易将不会通过。相反,它会恢复到原始状态,原因如下:
如果您只需要其他用户中的一个所有者,则使用 Ownable 智能合约很好。如果您正在寻找更多的层次结构,那么应该使用 AccessControl.sol 智能合约。
方法#4:访问控制
最后一个修复要求您通过 Open Zeppelin 访问 AccessControl 智能合约。
对于初学者,您必须将访问控制超链接添加到导入语句,并将“is AccessControl”添加到合同语句。
如前所述,此智能合约允许您在层次结构中添加许多角色,您必须声明这些角色,如下所示智能合约的前两行:
在这个合约中,有两个角色,即 Dunzo 和 Customer。现在,当您部署合约时,您必须将上述声明的角色分配给所述地址,以确定谁可以访问什么。此外,setPrice 和 setPackageDelivered 函数中添加了两个“require”语句。
如您所知,只有分配了 Dunzo 角色的帐户才能更改部署期间提到的销售条款,但不能更改任何其他帐户。也就是说,您可以使用 AccessControl.sol 为多个角色分配不同级别的智能合约功能访问权限,而 Ownable.sol 不会深入到那么多。
现在,这些并不是可用于在智能合约中实施访问控制的唯一解决方案。 RBAC.sol和WhitelistCrowdSale.sol过去也可用,它们也可以将角色与地址相关联,很像 AccessControl.sol 和 Ownable.sol。
因此,如果您想全面了解实施访问控制的演变过程,花时间仔细阅读这两个智能合约中的代码将是非常值得的。
也发布在这里。
本文的主图是由HackerNoon 的 AI Image Generator通过提示“访问被拒绝的生物识别扫描”生成的。