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


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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pmjgs0w0-1667370278953)(htTPS://tva1.sinaimg.cn/large/e6c9d24ely1h4r0auxvmxg20tr04ojug.gif)]

    什么是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 {}
    
    • 1
    • 2
    • 3
    • 4

    不正确的继承顺序

    继承中的钻石问题:

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

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

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

    contract Part1 {
      constructor() public {}
    }
    contract Part2 {
      constructor() public {}
    }
    contract Child is Part1, Part2 {
      constructor() public {}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    案例场景:

    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);
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

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

    这些检查器由合约“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带来的落地机遇。敬请关注我们的微信公众号 “去中心化金融社区”

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FzNmM6Pr-1667370278956)(htTPS://tva1.sinaimg.cn/large/e6c9d24ely1h4r0b7i2jnj20p00dw3zq.jpg)]

  • 相关阅读:
    孤儿僵尸守护进程
    Qt ---进程间的通信
    安全至上:落地DevSecOps最佳实践你不得不知道的工具
    基于Java实现的免疫算法-克隆选择算法
    2021icpc南京站
    手机也能轻松搭建个人博客,使用安卓Termux+Hexo建立自己的网站
    TDengine3.0 基础操作
    在windows server 2016安装Web服务器(IIS)
    RabbitMQ、Kafka对比(超详细),Kafka、RabbitMQ、RocketMQ的区别
    Visual Code 开发web 的hello world
  • 原文地址:https://blog.csdn.net/chinadefi/article/details/127650918