type
Post
status
Published
date
May 26, 2022
slug
game-live
summary
以太坊虚拟机 EVM 是智能合约的运行环境。
tags
区块链
开发
category
碎片杂文
icon
password
URL
以太坊虚拟机 EVM 是智能合约的运行环境。它不仅是沙盒封装的,而且是完全隔离的,也就是说在 EVM 中运行代码是无法访问网络、文件系统和其他进程的。甚至智能合约之间的访问也是受限的。

账户

两类账号:外部账户和合约账户,它们共用同一个地址空间。
  • 外部账户:有公钥决定
  • 合约账户:这个地址通过合约创建者的地址和从该地址发出过的交易数量计算得到的,也就是所谓的”nonce”
每个账户都有一个键值对形式的持久化存储。其中 key 和 value 的长度都是256位,我们称之为存储。
每个账户有一个以太币余额( balance )(单位是“Wei”),余额会因为发送包含以太币的交易而改变。

交易

可看作一个账户给另外一个账户发消息。能够宝行二进制数据(合约payload)和以太币。
如果目标地址为0,交易将会创建一个新合约。这个用来创建合约的交易的 payload 会被转换为 EVM 字节码并执行。执行的输出将作为合约代码被永久存储。这意味着,为创建一个合约,你不需要发送实际的合约代码,而是发送能够产生合约代码的代码。

Gas

一经创建,每笔交易都收取一定数量的 gas ,目的是限制执行交易所需要的工作量和为交易支付手续费。EVM 执行交易时,gas 将按特定规则逐渐耗尽。
gas price 是交易的发起者设置的,最终的手续费 = gas price * gas 。如果交易执行后还有剩余,gas 会原路返还。执行的时候,如果gas被耗尽,会触发 out-of-gas 异常。当前调用帧(call frame)所做的所有状态修改都将被回滚。
调用帧(call frame),指的是EVM的运行栈(stack)中当前操作所需要的若干元素。

存储,内存和栈

存储

每个账户有一块持久化内存区称为存储,是将256位字映射到256位字的键值存储区。在合约中枚举存储是不可能的,且读存储的相对开销很高,写存储的开销甚至更高。合约只能读写存储区内属于自己的部分。

内存

每次试图执行智能合约时候会申请一个刷新过的内存实例。
  • 线性,按照字节级别寻址,读取长度限制为256位,写可以使8位或者256位。
  • 访问之前未访问过的内存字(word)时,按照字进行扩展。扩容消耗gas,费用以使用量的平方级别进行增加。
一个字(word)为256位

EVM 不是基于寄存器的,而是基于栈的,所有计算都是在栈中执行。
  • 栈最大1024个元素,每个元素为一个字
  • 访问(所有操作都局限在栈顶的16个元素)
    • 允许copy栈最顶端16个元素中一个到栈顶。
    • 允许交换栈顶元素和下面16个元素中的一个。
    • 所有其他操作都只能取最顶的两个(或一个,或更多,取决于具体的操作)元素,运算后,把结果压入栈顶。

指令集

EVM指令集尽量少,以最大限度地避免可能导致共识问题的错误实现。
  • 所有操作都是256位的字。
  • 具备常用的算术、位、逻辑和比较操作。
  • 可以做到有条件和无条件跳转。
  • 合约可以访问当前区块的相关属性,比如它的编号和时间戳。

消息调用

合约可以通过消息调用的方式来调用其它合约或者发送以太币到非合约账户
  • 发送的消息包括一个源、目标、数据、以太币、gas和返回数据
  • 执行过程中如有 out-of-gas ,gas会被消耗掉(而不是退回?)。Solidity中,发起调用的合约默认会触发一个手工的异常,以便异常可以从调用栈里“冒泡出来”。
  • 被调用的合约(可以和调用者是同一个合约)会获得一块刚刚清空过的内存,并可以访问调用的payload(由被称为 calldata 的独立区域所提供的数据),执行完之后,返回数据保存在调用方预先分配好的一块内存中。
  • 调用深度最大为1024,复杂操作尽量用循环而非递归。

委托调用/代码调用和库

委托调用是一种特殊的消息调用。
区别在于目标地址的代码将在发起调用的合约的上下文中执行,并且 msg.sender 和 msg.value 不变。
相当于运行的时候动态时从另外一个地址动态加载代码。存储、当前地址和余额都指向发起调用的合约,只有代码是从被调用地址获取的。使得Solidity有库的能力。

日志

有一种特殊的可索引的数据结构,其存储的数据可以一路映射直到区块层级。这个特性被称为 日志(logs) ,Solidity用它来实现 事件(events)。因为部分日志数据被存储在 布隆过滤器(Bloom filter)  中,我们可以高效并且加密安全地搜索日志,所以那些没有下载整个区块链的网络节点(轻客户端)也可以找到这些日志。

创建

合约可以通过特殊指令来创建其他合约,称为create calls。
payload执行后,执行的结果被存储为合约代码,调用者/创建者在栈上得到新合约的地址。

自毁

合约代码从区块链上移除的唯一方式是合约在合约地址上的执行自毁操作 selfdestruct 。合约账户上剩余的以太币会发送给指定的目标,然后其存储和代码从状态中被移除。
尽管一个合约的代码中没有显式地调用 selfdestruct ,它仍然有可能通过 delegatecall 或 callcode 执行自毁操作。
主机游戏直播环境搭建Transformer 面试题目参考

Ross
Ross
这是关于Ross的百科。我将会在这里分享关于编程、机器学习、加密货币的相关内容,有时也会分享一些实用教程或者生活趣事。