面向开发者:Yul 与 Solidity 合约比较

面向开发者:Yul 与 Solidity 合约比较

未标题-3

img

概述

在本文中,我将使用Remix IDE,并将提供一些带有完整源代码的要点。虽然我将解释本文中使用的每个操作码,但最好阅读文档并在手边准备一个操作码表。

Yul

Yul是EVM操作码语言上的一个薄抽象层,可以在独立的Yul合约文件中使用,也可以通过一个assembly块在Solidity合约文件中使用。

function readWithYul() public view returns (uint256 data) {
assembly {
data := sload(0)
}
}

Yul的赋值操作符是:=,而不是Solidity中的=。每个操作码都有一组唯一的参数,这些参数可以通过操作码表找到。

然而,Yul不是一个可执行的二进制文件,这意味着它仍然需要编译才能在EVM中运行。在写这篇文章的时候,Yul可以编译成EVM操作码语言和eWASM, eWASM是未来几个月提出的用于ETH 2.0的操作码语言。

字节>类型

理解EVM使用32字节是很重要的,而Solidity类型只是在这些之上的一个抽象。Yul只定义了u256类型,表示256位无符号整数或32字节的字。

函数选择器

一个函数可以通过它的选择器访问。当我们通过区块链客户端库(如web3.js或ether .js)调用合约上的函数时,在底层会发生一些事情。

首先,生成函数签名。这是一个字符串,包含函数名称,后跟参数类型,逗号分隔,括在括号中。

// function declaration
function myFunc(uint256 param1, address param2) {}

// function signature
string signature = "myFunc(uint256,address)"

接下来,使用keccak256对函数签名进行哈希处理,并将其剪切到最左边的4个字节,以生成函数选择器。

// selector = 0x67adc20f
bytes4 selector = bytes4(keccak256(“myFunc(uint256,address)”));

因此,如果我们要调用这个函数,将数字42作为第一个参数,并将地址0x5B38…c4(缩短)作为第二个参数,那么编码后的有效负载可能看起来像是这样

0x67adc20f0000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4

如果我们把它拆开,我们会看到:

// hexadecimal prefix
0x

// selector for myFunc(uint256,address)
67adc20f

// number 42, padded to 32 bytes
0000000000000000000000000000000000000000000000000000000000000002a

// 0x5B38Da6a701c568545dCfcB03FcB875f56beddC4 padded to 32 bytes
0000000000000000000000005b38da6a701c568545dcfcb03fcb875f56beddc4

这在以后访问不同的函数时非常重要。

调用数据、堆栈、内存和存储

接下来,我们应该理解调用数据、堆栈、内存和存储。

当调用一个函数时,如上所述,编码的有效负载就是调用数据。我们可以访问calldata大小,即calldatasize(),我们可以阅读32个字节调用数据,calldataload(offset)其中offset是要读取calldata 中的起始位置,我们可以将调用数据复制到内存里,calldatacopy(destOffset, offset, size)其中destOffset是要复制内存中的起始位置,offset是要复制调用数据中的起始位置,复制的调用size数据中的字节数。

该堆栈包含32个字节字,堆栈深度为1024,函数与任何其他堆栈一样。我们可以像在任何其他堆栈上一样,推送、弹出、交换和执行算术运算。Yul为我们处理了很多这方面的工作,因此通过push和pop操作码直接与堆栈交互超出了本文的讨论范围。

内存是线性的,可以暂时存储数据,但在消息调用之间会被清除。可以使用mstore8(offset, value),以 8 位为增量写入内存,其中offset是内存中的起始位置,value是要存储的 8 位值,或者以 256 位为增量,使用mstore(offset, value),其中offset是内存中的起始位置,value是要存储的 256 位值。想从内存中读取,可以通过内存中的mload(offset),其中offset是起始位置。从内存中读取总是会返回到从偏移量开始的256位。与内存交互的gas成本与存储在内存中的数据的大小成二次方关系。

存储在函数调用之间是持久的,也称为状态。存储由键/值对组成,其中键和值都是256位字。写入状态是通过sstore(key, value)完成的,其中key是存储的位置,value是存储在给定键位置的256位值。从存储中读取数据可以用sload(key)来完成,其中key是存储所需值的位置。从gas的角度来说,读取和写入存储是最昂贵的。更多的细节可以在下面的EVM操作码链接中找到。

链接

交互式操作码表:https://www.evm.codes/

Yul Doc:https://docs.soliditylang.org/en/v0.8.11/yul.html

合约

在本文的范围内,我们将编写一个合约,其中有一个状态变量、一个读取函数、一个写入函数、一个回退函数,以及在写入状态变量时发出的单个事件。

SolidityContract.sol

对于Solidity开发人员来说,这将是不言自明的,但是为了清晰起见,我们将简要地回顾一下代码。像往常一样&#

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值