宇宙链 宇宙链
Ctrl+D收藏宇宙链

EVM 深入探讨

作者:

时间:1900/1/1 0:00:00

导语

在智能合约世界中,“以太坊虚拟机”及其算法和数据结构是首要原则。我们创建的智能合约就是建立在这个基础之上的。不管是想要成为一名出色的Solidity智能合约开发人员还是安全人员都必须对EVM有深入的了解。

此系列我们将引介翻译noxx的文章,深入探讨EVM的基础知识。

基础知识:Solidity→字节码→操作码

在阅读本篇文章之前,你需要了解一些智能合约相关基础知识以及如何将智能合约代码部署到以太坊链上。正如我们所知,智能合约在部署到以太坊网络之前需要先将Solidity代码编译成字节码,EVM会根据编译后的字节码执行相应的操作。本篇重点介绍编译后的字节码以及其如何被EVM执行的。

智能合约被部署后编译生成的字节码代表了整个合约的内容,其中存在多个可调用的函数。那么EVM是如何知道不同函数所对应的字节码是哪个呢?下面我们将通过一个Solidity智能合约及其字节码和操作码来向大家演示EVM在执行代码时是如何在字节码中选择对应的函数的。

1_Storage.solBreakdown

我们使用在线SolidityIDE工具Remix来编译Storage合约。

此合约中存在两个函数store()和retrieve(),在进行函数调用时EVM需要判断我们调用的是哪个函数。我们可以通过remix看到整个合约编译后的字节码。

Kava宣布完成Kava 13主网升级,上线Kava EVM 2.0:5月18日消息,据官方推特,Kava Chain宣布Kava 13主网已于2023年5月18日推出,此次升级重点在于上线Kava EVM 2.0、增加Cosmos SDK和EVM链上的钱包和DApp及资产的实用性、Strategic Vault (战略金库) 管理升级。[2023/5/18 15:10:49]

下面这段字节码是我们需要重点关注的,这段就是EVM判断被调用函数的选择器。与其对应的是EVM操作码及输入值。

我们可以通过Ethervm.io来查看EVM操作码列表。一个操作码长度为1个字节,这使得它可以存在256种不同的操作码。但EVM仅使用其中的140个操作码。

下面是我们将上述字节码解析成与其对应的操作码。这些操作码会由EVM在调用栈上按顺序执行。

智能合约函数调用

在深入研究操作码之前,我们需要快速了解如何调用合约中的函数。调用智能合约中的函数有以下方式:

abi.encode(...)returns(bytes):计算参数的ABI编码。

abi.encodePacked(...)returns(bytes):计算参数的紧密打包编码。

abi.encodeWithSelector(bytes4selector,...)returns(bytes):计算函数选择器和参数的ABI编码。

abi.encodeWithSignature(stringsignature,...)returns(bytes):等价于?abi.encodeWithSelector(bytes4(keccak256(signature),...)。

0VIX:正在调查疑与 vGHST 有关的情况,已暂停 POS 与 zkEVM 市场:4月28日消息,Polygon 生态项目 0VIX Protocol 发推称,正在与安全伙伴合作,调查目前似乎与 vGHST 有关的情况。因此,POS 和 zkEVM 市场已经暂停,包括暂停 oToken 的转移、铸造与清算。目前只有 POS 受到影响,但 zkEVM 已经暂停以作预防,并可能很快再次启用。[2023/4/28 14:33:34]

abi.encodeCall(functionfunctionPointer,(...))returns(bytesmemory):使用tuple类型参数ABI编码调用functionPointer()。执行完整的类型检查,确保类型匹配函数签名。结果和?abi.encodeWithSelector(functionPointer.selector,(...))一致。

这里我们以第四种为例,调用store()并传入参数10:

下面是通过?abi.encodeWithSignature("store(uint256)",10)?编码后的内容:

这段数据就是编码后的函数签名。

我们可以使用在线工具来查看?store(uint256)和?retrieve()哈希后的结果。

V神:ZK-EVM是以太坊Layer 1安全和验证过程的重要组成部分:金色财经报道,以太坊联合创始人“V神”Vitalik Buterin在其官方博客上发布文章《以太坊的多客户端理念将如何与ZK-EVM交互?》(How will Ethereum's multi-client philosophy interact with ZK-EVMs?),其中指出ZK-EVM将在未来发展成为以太坊Layer 1安全和验证过程的重要组成部分,但关键在于如何为零知识证明以太坊区块的正确性创建一个“多客户端”生态系统。V神建议采取开放的多个ZK-EVM,因为不同的客户端有不同的ZK-EVM实现,每个客户端可以在接受一个区块为有效之前等待与自己兼容的证明。此外,Vitalik Buterin还对人工智能最近的快速发展大加赞扬,他觉得人工智能的进步可以“加速”证明ZK-EVM实现的发展。“从长远来看,当然任何事情都有可能发生。也许AI会加强形式验证,使其可以轻松证明ZK-EVM实现等效并识别导致彼此之间差异的所有错误。”[2023/4/2 13:40:23]

也可以通过以太坊函数签名数据库进行反查。

Cardano推出EVM兼容侧链工具包:3月6日消息,Cardano背后开发公司Input Output Global(IOG)宣布推出自定义EVM兼容侧链工具包,目前概念验证版已上线测试网,该工具包由三个核心组件,分别是:Mainchain Plutus脚本(支持安全的跨链交易和代币移动)、链上追踪器(跟踪管理侧链的主链数据和事件)、侧链模块(解释主链数据并实施必要的账本调整),开发人员将能够为Cardano构建自定义侧链,继而支持更多链上功能和可扩展性。(Micky)[2023/3/6 12:45:27]

再回到上面的那组函数签名数据,其中前4个字节对应的是store(uint256)。而剩余的32个字节则对应的是一个十六进制的值“a”,也就是我们调用函数时传入的uint256类型的10。

这里我们可以得到一个结论,通过?abi.encodeWithSignature()?编码后得到的数据,共36个字节。这36个字节的数据就是函数签名,其中前4个字节为函数选择器,它将指引EVM去选择我们调用的目标函数,后32个字节的数据则是我们调用函数时传入的参数。

操作码和调用栈

这里相信大家已经大致了解了智能合约中函数调用的原理了,下面我们将通过解读每个操作码的作用及其对栈调用的影响。如果你不熟悉栈数据结构的工作原理,可以观看此视频来快速入门:https://www.youtube.com/watch?v=FNZ5o9S9prU

我们将得到的字节码分解成相对应的操作码后依次开始分析。

?PUSH1操作,将一个?1字节的值压入栈,它会告诉EVM将下一个数据字节0x00?压入栈中。

Evmos宣布将上线计划往后推迟24小时,将于4月27日重新上线:4月26日消息,Cosmos EVM兼容中心Evmos宣布将上线计划往后推迟24小时,将于4月27日重新上线,以确保所有验证节点做好100%的准备。

此前报道,Evmos于3月7日升级失败之后暂停网络,计划于4月26日重新上线。[2022/4/26 5:12:12]

接下来是CALLDATALOAD,其作用是从消息数据中读取32个字节的值,其中使用“输入”值作为偏移量将calldata加载到栈中。栈项大小为32字节,但是当前我们的calldata有36个字节。推送的值是msg.data其中“i”就是这个输入值。此操作确保只有32个字节被推送到栈,同时也能保证我们能够访问calldata中的任何部分。

当前输入值为0也就是没有偏移量,因此calldata的前32个字节会被推送到调用栈。

还记得之前所获取到的函数签名吗?如果要传入这36个字节,这就意味着后面的4个字节“0000000a”将会丢失。如果想访问这个uint256类型的参数,需要设置4的偏移量来省略函数签名,这样就可以保证参数的完整性。

第二次进行PUSH1的操作将传入十六进制的数据0xe0,也就是十进制的224。我们上面提到过,函数签名是4个字节也就是32位。我们加载的calldata是32个字节也就是256位,而256-32=224正好满足。

SHR,是向右移位指令。它从栈中获取第一项224表示要位移的位数,从栈中获取第二项??表示需要移位的内容。在这个操作之后调用栈上有了4个字节的函数选择器。

如果对于位移的工作原理不熟悉的小伙伴,可以查看这个视频了解:https://www.youtube.com/watch?v=fDKUq38H2jk&t=176s

接下来的操作码,DUP1,它用来获取并复制栈顶部的值。

PUSH4将?retrieve()(0x2e64cec1)的4个字节函数签名推入调用栈。

如果你好奇是这个值是如何获得的,那是因为solidity代码被编译成字节码中。编译器可以从字节码中获取所有函数名称和参数类型的信息。

EQ用于判断从栈中弹出的2个值,在当前事例中为0x2e64cec1和0x6057361d并检查它们是否相等。如果相等,则将1推回栈,如果不相等则为0。

PUSH2将2字节的十六进制数据0x003b,十进制值为59,推送到调用栈中。

调用栈中有一个叫做程序计数器的东西,它会指定下一个执行命令在字节码中的位置。这里的59,是通过retrieve()?字节码的开始位置所得到的。

JUMPI代表“如果条件为真,则跳转”,它从栈中弹出2个值作为输入,第一个59表示的是跳转位置,第二个0是是否应该执行此跳转条件的布尔值。其中1为真,0为假。

如果条件为真,程序计数器将被更新,执行将跳转到该位置。但我们的例子中条件为假的,程序计数器没有改变并且继续执行。

再次进行DUP1。

PUSH4将store(uint256)(0x6057361d)?的4字节函数签名推送到调用栈上。

再次进行EQ,但这次结果为真,因为函数签名相同。

PUSH2推送2个字节的十六进制数据?0x0059也就是十进制的89,到store(uint256)字节码的程序计数器位置。

执行JUMPI,此次bool值为真,执行跳转。因此会将程序计数器更新为89,这会将执行移动到字节码的不同部分。在这个位置,会有一个JUMPDEST操作码,如果没有这个操作码在这里的话,JUMPI操作就会失败。

有了它,在执行此操作码后,将被带到store(uint256)?对应的字节码的位置,并且函数的执行将继续。虽然这个合约只有2个函数,但基础原理都是相同的。

通过上面的例子我们知道了EVM是如何根据合约函数调用来确定它需要执行的函数字节码的位置。简单来说就是由合约中每个函数及其跳转位置所组成的一组简单的“if语句”。

EVMPlayground

这是一个EVMPlayground测试平台,在平台上我们可以设置刚刚运行的字节码。就能够通过交互方式来查看栈的变化,并且传入JUMPDEST,可以看到JUMPI之后会发生什么。

EVMPlaygrpund还能有助于我们理解程序计数器的运行,每条命令旁都能看到相对应的注释以及偏移量所代表的程序计数器的位置,同时在左边框内还能看到calldata的输入。当点击运行指令,可以通过右上角的箭头单步调试每个操作码例如更改为retrieve()?调用数据0x2e64cec1来查看执行的变化。

敬请期待《EVM深入探讨-Part2》,让我们共同探索合约内存是什么以及它在EVM下的工作方式。

标签:TORINTSTORRETProtectors of the Realmcointiger官网下载最新版本STORJCRETH2

以太坊价格今日行情热门资讯
金色早报 | 加密总市值重回1万亿美元上方

头条 ▌加密总市值重回1万亿美元上方金色财经报道,据CMC最新数据显示,BTC价格已重新反弹至2万美元上方,当前为20,079.55美元,24小时涨幅0.3%。ETH当前为1,587.34美元,24小时涨幅2.2%.

1900/1/1 0:00:00
V 神发布新作 如何领取其首个新书灵魂绑定代币?

本文作者:0x711,BlockBeats8月31日,V神在其社交平台表示,其近十年所有文字内容组成的文集《ProofofStake》数字版和实物版将出版.

1900/1/1 0:00:00
Paradigm:公链数据可用性采样(DAS)技术的挑战与未来研发方向

注:原文作者JoachimNeuJoachim-Neu是Paradigm的研究实习生,他也是斯坦福大学的区块链科学博士生,目前他的研究重点是可证明共识安全。 简介 任何L1区块链的核心职责是保证数据可用性.

1900/1/1 0:00:00
NFT协议除了ERC721 还有什么?一文盘点现有NFT协议

原文:《A&TView:一览现有的NFT协议》作者:A&TCapital统一的链上协议标准可有效降低NFT资产发行的门槛和难度,解决NFT市场中的资产安全、真伪性、流动性和去中心化问题.

1900/1/1 0:00:00
金色晨讯 | 9月9日隔夜重要动态一览

21:00-7:00关键词:9月加息、CardanoNFT、鲍威尔、Arweave1.美国证交会将成立一个新的负责加密披露的办公室;2.美国财政部将建议政府采用数字美元;3.

1900/1/1 0:00:00
Web3 驱动的分布式计算网络如何成为元宇宙重要基建?

短期来看,Web3驱动的分布式算力的实现难度高,但是中长期看,这个是一个必然的结果和选择。原文标题:《A&T前瞻:为什么Web3驱动的分布式算力网络是元宇宙的基础设施?》撰文:Rosie,A&TCapital高级投资经.

1900/1/1 0:00:00