智能合约Solidity学习-低级别调用

130 阅读2分钟

智能合约在EVM系统中的存在形式

  • 代码中的函数被调用时可以修改存储空间中的状态变量
  • 代码本身无法修改
  • 存储空间的结构无法任意安排

20230408172658.png

存储结构

合约的存储结构是一个总大小为2的256次幂的插槽空间,每一个插槽大小为32Bytes(256 Bits)

  • 插槽位置按照状态变量的顺序依次分配
  • 插槽没有"名字"的概念,只有位置
  • 定长类型变量直接存储在分配的插槽
  • 变长类型变量将计算出实际存储位置
  • 如果字符串长度<=31Bytes,则直接存储在高位,length*2存储在末尾
  • 如果字符串长度>31Bytes,则原槽位存储length*2+1,数据存储在keccak256(slot)

1680508319033.png

微信截图_20230408174157.png

数据读取的消耗

占用空间小的变量类型是否使用时更节省gas?不是

uint128 number uint256 longNumber

EVM读取存储数据时以32Bytes为单位读取

  • 读取number:先读取出该存储插槽的数据,在再截取一半的长度得到number本身
  • 读取longNumber:直接读取该存储插槽的数据便可以使用

跨合约调用

一笔链上交易的流程

1680509051956.png

  • 交易只能由EOA账户发起
  • 调用=执行代码+修改状态

三种跨合约调用方式(Call DelegateCall StaticCall)

关键核心执行谁的代码&&修改谁的状态

  • 调用的是view函数 - static call
  • 调用的是普通函数 - call
  • 调用的是链接的Library函数 - delegate call

1680509201192.png

跨合约调用-两种层级的调用方式

高等级调用

High-level Call 通过引入接口或合约获得函数名称和参数类型,直接使用函数名称和参数来调用

1680944065935.png import"interface.sol"
interface(address).functionName(parameters...)

低等级调用

Low-level Call 直接使用函数签名(function signature)来调用,无需引入接口

(bool success,bytes memory data)=address.call(function signtrue)
call 可以换成 delegatecall 或者 staiccall

函数签名 = 函数选择器 + 参数

例如:函数为myFunction(uint256)
函数选择器 Function Selector = abi.encodeWithSelector("myFunction(uint256)")
Function Selector= bytes4(keccack256(byres("myFunction(uint256)")))
函数签名 Function Signature = abi.encodeWithSignature("myFunction(uint256)",1)

特点:

  • 无需引入接口
  • 没有编译时的类型检查
  • 调用出现错误时不会抛出异常
  • 需要手动解码返回值