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

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

什么是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篇内容中,寻找思考更具深度、梳理更为系统的内容,以最快的速度同步到中国市场提供决策辅助材料。

本文首发于:https://mp.weixin.qq.com/s/c2abX-jm-NfBN3sC7oEIFg

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

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