Solidity:智能合约中不正确的继承顺序

去中心化金融社区2022-11-02 14:23



什么是 Solidity 中的多重继承?

Solidity 允许多重继承,包括多态性。

函数调用,无论是内部的还是外部的,都将始终在继承树中派生最多的合约中执行具有相同名称(和参数类型集)的函数。必须使用 virtual 和 override 关键字显式启用层次结构中的每个函数。

通过使用 ContractName.functionName() 显式定义合约,或者如果想在扁平继承层次结构中调用更高一级的函数,则可以在内部调用继承层次结构中更高一级的函数。

当一个合约从另一个合约继承时,所有基础合约的代码会被编译到新形成的合约中,这是在区块链上创建的唯一合约。因此,任何基本合约函数的内部调用同样只使用内部函数调用 (super.f(..) 将使用 JUMP 而不是消息调用 )。

下面是合约如何相互继承的例子:

pragma solidity ^0.8.0;contract X {}contract Y is X {}contract C is Z, X {}

不正确的继承顺序

继承中的钻石问题

Solidity 支持多重继承,允许一个合约继承多个合约。多重继承造成了一种被称为钻石问题的模糊性:如果两个或多个合约定义了相同的函数,那么应该在子合约中调用哪个基础合约?

Solidity 通过使用反向 C3 线性化解决了这种困境,它在基本合约之间建立了层次结构,主要用于确定在存在多重继承的情况下应该以何种顺序继承方法。

这意味着在下面所示的合约中,Child 合约将按照 Child -> Part2 -> Part1 的顺序从其他合约继承。

contract Part1 {  constructor() public {}}contract Part2 {  constructor() public {}}contract Child is Part1, Part2 {  constructor() public {}
}


案例场景

pragma solidity 0.5.17; contract adminChecker {    address admin = msg.sender;   function roleCheck() internal view returns (bool) {       return msg.sender == admin;   }} contract guestChecker {    address guest = msg.sender;   function roleCheck() internal view returns (bool) {       return msg.sender == guest;   }} contract ownersCanKill is adminChecker, guestChecker {    function kill() external{       require(roleCheck(), "Not an Admin");       selfdestruct(msg.sender);   }}

在上面的示例中,有两个角色检查合约。其中一个检查调用者是否具有管理角色,另一个检查调用者是否具有访客角色。如果语句为 true,这两个函数都返回 true。

这些 checker 由合约“ownersCanKill”继承。继承顺序在这里很重要,因为它将决定调用哪个“roleCheck()”函数。

理想情况下,访客不应该能够调用" kill() "函数,但根据 C3 线性化,函数调用将遵循以下路径:

ownersCanKill.kill()→guestChecker.roleCheck()→adminChecker.roleCheck ()

这将导致意想不到的行为,并允许访客“自毁”合约,并将所有的资金转移到他们的账户。

然而,这在 Solidity 0.6.0+ 上是行不通的,而且编译器会在模棱两可的函数上抛出错误。

在 Solidity 中继承的最佳实践

C3 线性化

当存在多重继承时,主要利用 C3 超类线性化算法来确定方法的继承顺序。

开发人员应该记住顺序。这将是定义函数从何而来的决定性因素。

父函数被调用

如果开发人员想要专门调用父合约中定义的函数,他们可以在函数调用中使用super关键字:super.func()。

这将指示 EVM 使用父合约中定义的' func() ',完全忽略子合约中的任何定义。

一个函数,多种形式

合约可以有多种形式,函数也可以有多种形式,这就是多态性所需要的。只要它们的签名不同,就可以拥有许多具有相同名称的函数,这是多态性最好的优点之一。实际上,这相当于只有一个函数,但这个函数有多种表现形式。

结论

开发人员可以使用 Solidity 继承函数、状态变量和函数修饰符。Solidity 也通过函数重写支持多态性。当多个继承合约定义具有相同名称和参数类型的函数时,可能会产生歧义。在应用程序中实现函数重写时,不要忘记使用 virtual 和 override 这两个词。

Source:https://blog.solidityscan.com/incorrect-inheritance-order-in-smart-contracts-ddcc75ed472c

关于

ChinaDeFi - ChinaDeFi.com 是一个研究驱动的 DeFi 创新组织,同时我们也是区块链开发团队。每天从全球超过 500 个优质信息源的近 900 篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。

Layer 2 道友 - 欢迎对 Layer 2 感兴趣的区块链技术爱好者、研究分析人与 Gavin(微信: chinadefi)联系,共同探讨 Layer 2 带来的落地机遇。敬请关注我们的微信公众号 “去中心化金融社区”。



【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。

来源链接

相关Wiki

相关标签