惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
罗磊的独立博客
H
Help Net Security
I
Intezer
G
Google Developers Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
T
Troy Hunt's Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
U
Unit 42
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
N
News and Events Feed by Topic
J
Java Code Geeks
S
Security Affairs
T
The Blog of Author Tim Ferriss
Recent Commits to openclaw:main
Recent Commits to openclaw:main
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
D
Docker
The GitHub Blog
The GitHub Blog
F
Full Disclosure
N
News and Events Feed by Topic
Webroot Blog
Webroot Blog
S
Security @ Cisco Blogs
腾讯CDC
人人都是产品经理
人人都是产品经理
M
MIT News - Artificial intelligence
Blog — PlanetScale
Blog — PlanetScale
T
Threatpost
D
DataBreaches.Net
Recent Announcements
Recent Announcements
博客园 - 三生石上(FineUI控件)
MongoDB | Blog
MongoDB | Blog
博客园 - 【当耐特】
L
LINUX DO - 最新话题
Google Online Security Blog
Google Online Security Blog
S
Schneier on Security
S
Securelist
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Help Net Security
Help Net Security
P
Proofpoint News Feed
Project Zero
Project Zero
S
SegmentFault 最新的问题
H
Hackread – Cybersecurity News, Data Breaches, AI and More
MyScale Blog
MyScale Blog
Google DeepMind News
Google DeepMind News
宝玉的分享
宝玉的分享
Y
Y Combinator Blog
C
CXSECURITY Database RSS Feed - CXSecurity.com
博客园 - 叶小钗

博客园 - HorseShoe2016

Ethereum 学习笔记 ---- Solidity 数据位置(Calldata, Memory, Storage)编码与布局全解析 vscode 禁用警告提示音 浏览器加载 HTML 页面并执行 Javascript 的流程图 Ethereum学习笔记 ---- 使用 Remix 调试功能理解 bytes 在 memory 中的布局 Ethereum学习笔记 ---- 通过 Event 学习《合约ABI规范》 Javascript: Blob, File/FileReader, ArrayBuffer, ReadableStream, Response 转换方法 vscode 无法调试 golang testify suite 中的单个 test 的解决办法 纯js实现 vue 组件 与 vue 单文件组件对比 一个简单的 indexedDB 应用示例 html 元素的 onEvent 与 addEventListener vue3 defineComponent: 使用纯 Javascript 定义组件 vue3 动态编译组件失败:Component provided template option but runtime compilation is not supported in this build of Vue Javascript Object 中,isExtensible/isSealed/isFrozen 的对比 mini-vue: 响应式数据的实现 手写Promise vscode vue 插件与 emmet、tailwind css 插件冲突的解决方案 Python 安装依赖包,出现 ssl.SSLCertVerificationError 的问题,解决方法 CentOS7 源码编译安装 Python 3.8.10,开启 SSL 功能 Protocol Buffer Go (proto3) - macos 搭建 protocol buffer 环境 + Encoding 实验
Ethereum学习笔记 ---- 多重继承中的 C3线性化算法
HorseShoe2016 · 2024-09-12 · via 博客园 - HorseShoe2016

学习 solidity 合约多重继承时,官方文档介绍 solidity 采用 C3线性化算法 来确定多重依赖中的继承顺序。
维基百科上有很好的说明:
C3线性化
C3 linearization

下面通过实验来深入理解一下。

举个反例

在 c3_notok.py 中定义如下类

class Type(type):
    def __repr__(cls):
        # Will make it so that repr(O) is "O" instead of "<__main__.O>",
        # and the same for any subclasses of O.
        return cls.__name__

class O(object, metaclass=Type): pass

class A(O): pass

class X(O, A): pass

if __name__ == '__main__':
    print(X.mro())

执行会 throw error:

$ python3 c3_notok.py

TypeError: Cannot create a consistent method resolution
order (MRO) for bases O, A

分析错误原因

根据 C3 线性化算法,计算 X 的 mro (Method Resolution Order):

L(O) := [O]

L(A) := [A] + merge(L(O), [O])
     := [A] + merge([O], [O])
     := [A, O]

L(X) := [X] + merge(L[O], L[A], [O, A])
     := [X] + merge([O], [A, O], [O, A])

可以看到在最后一步计算中, OA[A, O], [O, A] 两个列表中分别为 head 和 tail,算法无法继续进行下去,所以 class X(O, A) 的定义不合法。

举个正例

在 c3_ok.py 中定义如下

class Type(type):
    def __repr__(cls):
        # Will make it so that repr(O) is "O" instead of "<__main__.O>",
        # and the same for any subclasses of O.
        return cls.__name__

class O(object, metaclass=Type): pass

class A(O): pass

class X(A, O): pass

if __name__ == '__main__':
    print(X.mro())

执行脚本,可以看到正常的输出结果:

$ python3 c3_ok.py 
[X, A, O, <class 'object'>]

分析

根据 C3 线性化算法,计算 X 的 mro:

L(O) := [O]

L(A) := [A] + merge(L(O), [O])
     := [A] + merge([O], [O])
     := [A, O]

L(X) := [X] + merge(L[A], L[O], [A, O])
     := [X] + merge([A, O], [O], [A, O]) 
     := [X, A] + merge([O], [O], [O])
     := [X, A, O]

solidity 中的多重继承

需要注意的是,在 solidity 中定义合约时,如果是多重继承,parent contracts 的顺序跟 python 中的 parent classes 的顺序是相反的,即 farthest parent contract 应该书写得离当前定义的合约最近,如下:

contract O {}

contract A is O {}

contract X is O, A {}

多重继承合约的 storage layout

remix 中编写如下合约

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.8.0 <0.9.0;

import "hardhat/console.sol";

struct UintStruct {
    uint value;
}

contract O {
    uint v0 = 0;
}

contract A is O {
    uint v1= 1;
}

contract B is O {
    uint v2= 2;
}

contract C is O {
    uint v3= 3;
}

contract D is O {
    uint v4= 4;
}

contract X1 is O, A, B, C, D {
    uint vx1 = 6;

    function showStorageInX1() public view {
        UintStruct storage us;
        uint i;
        for (; i < 6; ++i) {
            assembly {
                us.slot := i
            }
            console.log(i, us.value);
        }
    }
}

contract X2 is A, B, C, D {
    uint vx2 = 7;

    function showStorageInX2() public view {
        UintStruct storage us;
        uint i;
        for (; i < 6; ++i) {
            assembly {
                us.slot := i
            }
            console.log(i, us.value);
        }
    }
}

可以看到, OABCD 合约的共同 parent contract,而 X2X1 少继承了一个 O

部署两个合约,分别调用两个合约中的函数 showStorageInX1()showStorageInX2(),结果如下:

可以看到,X1 和 X2 的 storage layout 是一样的,所以,在多重继承定义中,其实可以省略公共 parent contract。

posted on 2024-09-12 16:29  HorseShoe2016  阅读(256)  评论()    收藏  举报