• solidity 存储 /变量


    EVM里有5个地方涉及存储

    • Storage/存储
    • 存储中的数据是永久存在的。存储是一个key/value库- 存储中的数据写入区块链,因此会修改状态,这也是存储使用成本高的原因。
    • 占用一个256位的槽需要消耗20000 gas
    • 修改一个已经使用的存储槽的值,需要消耗5000 gas
    • 当清零一个存储槽时,会返还一定数量的gas
    • 存储按256位的槽位分配,即使没有完全使用一个槽位,也需要支付其开销
    • 底层指令为 SSTORE and SLOAD
    • Memory/内存
    • 内存是一个字节数组,槽大小位256位(32字节)
    • 数据仅在函数执行期间存在,执行完毕后就被销毁
    • 读或写一个内存槽都会消耗3gas
    • 为了避免矿工的工作量过大,22个操作之后的单操作成本会上涨
    • 底层代码MLOADMSTORE, and MSTORE8.
    • CALLDELEGATECALL or STATICCALL 操作也会通过参数消耗内存
    • Calldata/调用数据
    • 调用数据是不可修改、非持久化的区域,用来保存函数参数,其行为类似于内存
    • 外部函数的参数必须使用calldata,但是也可用于其他变量
    • 调用数据避免了数据拷贝,并确保数据不被修改
    • 函数也可以返回使用calldata声明的数组和结果,但是不可能分配这些类型
    • 底层代码 CALLDATALOADCALLDATASIZE and CALLDATACOPY.
    • Stack/堆栈
    • stack存储函数里的本地变量
    • 大小限制:
    • 底层指令USHPOPSWAP and DUP

    • Code
    • 合约代码,bytecode编码
    • 只能读,不可写
    • 底层代码,读取代码 CODESIZE and CODECOPY. 操作代码 EXTERNALCODESIZE and EXTERNALCODECOPY.

     

    数据的位置-规则

    变量的默认位置 

    根据变量在代码里定义的位置,solidity会默认给出存储位置

    1. # 变量定义为 constant = 相当于合约代码 (= bytecode).
    2. # state 变量(在函数外面定义) = in storage by default.
    3. # 本地变量local variables (函数体内定义) = in the stack.

    通常情况下,代码里无需声明变量类型,solidty会根据定义变量的位置来确定类型

    不过,像函数里的struct 和 arrays, 需要声明变量存储类型

    赋值

    • 在存储storage和内存memory(或调用数据calldata)间的赋值将创建一个新的独立拷贝
    • 内存memory之间的赋值仅创建引用,这意味着对一个内存memory变量的修改会
      同时反应在其他引用相同数据的内存memory变量上
    • 从存储storage到局部存储变量的赋值,实际上只会给一个引用
    • 所有其他赋值通常导致产生新的数据拷贝。例如赋值给状态变量
      或位于存储storage的结构类型的局部变量成员时,即使局部变量只是一个

    引用类型

    对于数组(无论边长还是定长,诸如 unit256[]),bytes, strings,struct 和 mapping ,需要严格声明存储位置(storagememory or calldata)

    以下3种情况,需要声明存储位置

    • 函数参数(函数定义时)
    • 函数内部定义的局部变量
    • 返回类型始终都存储在memory

    Rules for function parameters

    Rules for the Function Body

    函数内部,所有数据存储类型都可以定义,无论函数是否可见

    不同类型的变量

    Inside functions, all three data locations can be specified, no matter the function visibility.

    However, assignments between reference types are bound to specific rules. (Here is where it gets complicated and “slightly tongue twisting!”).

    1. // SPDX-License-Identifier: Apache-2
    2. pragma solidity ^0.8.0;
    3. contract StorageReferences {
    4. bytes someData;
    5. function storageReferences() public {
    6. bytes storage a = someData;
    7. bytes memory b;
    8. bytes calldata c;
    9. // storage 变量可以引用另外一个 storage 变量(必须初始化过)
    10. bytes storage d = a;
    11. // 如果 storage 的引用没有初始化,将会报错
    12. // 错误信息 "This variable (refering to a) is of storage pointer type and can be accessed without prior assignment, which would lead to undefined behaviour."
    13. // f -> e -> (nothing) ??? 不能创建storage 引用指向了未知(nothing)
    14. /// bytes storage e;
    15. /// bytes storage f = e;
    16. // storage 指针不能指向 memory 指针(不管memory指针是否已经初始化)
    17. /// bytes storage x = b;
    18. /// bytes memory r = new bytes(3);
    19. /// bytes storage s = r;
    20. // storage 指针不能指向 calldata 指针(不论calldata指针是否已经初始化)
    21. /// bytes storage y = c;
    22. /// bytes calldata m = msg.data;
    23. /// bytes storage n = m;
    24. }
    25. }

    参考

    Ethereum: Datastore types explained

    Solidity Tutorial: All About Data Locations

  • 相关阅读:
    大一新生HTML期末作业 学生个人网页设计作业 HTML5响应式个人简历网站模板 web前端网页制作课作业
    24、Flink 的table api与sql之Catalogs(java api操作视图)-3
    valgrind 工具使用
    CPU以及与CPU配合的存储体系
    [深度学习论文笔记]医学图像分割U型网络大合集
    在 Windows 操作系统中,可以通过命令行工具来杀死进程
    计算机毕业设计Java银创科技有限公司人事信息系统(系统+程序+mysql数据库+Lw文档)
    【毕业设计源码】基于Python的校园生活助手(二手+活动+论坛+新闻)信息系统
    MySQL索引
    读后感读后感读后感
  • 原文地址:https://blog.csdn.net/linzhiji/article/details/127806639