以太坊虚拟机 EVM 是智能合约的运行环境。它不仅是沙盒封装的,而且是完全隔离的,也就是说在 EVM 中运行代码是无法访问网络、文件系统和其他进程的。甚至智能合约之间的访问也是受限的。
Ether's virtual machine, EVM, is the operating environment for smart contracts. It's not just a sandbox, it's completely isolated, that is, running a code in EVM without access to networks, file systems, and other processes. Even access between smart contracts is limited.
以太坊中有两类账户(它们共用同一个地址空间): 外部账户 由公钥-私钥对(也就是人)控制; 合约账户 由和账户一起存储的代码控制.
There are two types of accounts in Etheria (which share the same address space):
外部账户的地址是由公钥决定的,而合约账户的地址是在创建该合约时确定的(这个地址通过合约创建者的地址和从该地址发出过的交易数量计算得到的,也就是所谓的“nonce”) The address of the external account is determined by the public key, whereas the address of the contractual account was determined at the time of the creation of the contract (the address is calculated by the address of the originator of the contract and the number of transactions from that address, the so-called “nonce”) 无论帐户是否存储代码,这两类账户对 EVM 来说是一样的。 These two types of accounts are the same for EVM regardless of whether or not the account contains the code. 每个账户都有一个键值对形式的持久化存储。其中 key 和 value 的长度都是256位,我们称之为 存储 。 Each account has a key-to-key permanent storage. The key and value are 256 in length, which we call storage strong>. 此外,每个账户有一个以太币余额( balance )(单位是“Wei”),余额会因为发送包含以太币的交易而改变。 In addition, each account has a balance in tae currency (balance) (in “Wei”), which is subject to change as a result of sending transactions containing tae currency.
交易可以看作是从一个帐户发送到另一个帐户的消息(这里的账户,可能是相同的或特殊的零帐户,请参阅下文)。它能包含一个二进制数据(合约负载)和以太币。
A transaction can be seen as a message sent from one account to another (the account here may be the same or special zero account, see below). It can contain a binary data (contract load) and a taser.
如果目标账户含有代码,此代码会被执行,并以 payload 作为入参。
If the target account contains a code, the code is executed with payload as input.
如果目标账户是零账户(账户地址为 ),此交易将创建一个 新合约 。 如前文所述,合约的地址不是零地址,而是通过合约创建者的地址和从该地址发出过的交易数量计算得到的(所谓的“nonce”)。 这个用来创建合约的交易的 payload 会被转换为 EVM 字节码并执行。执行的输出将作为合约代码被永久存储。这意味着,为创建一个合约,你不需要发送实际的合约代码,而是发送能够产生合约代码的代码。
If the target account is zero (the account address is), the transaction will create a new contract strong >. As noted earlier, the address of the contract is not zero, but is calculated by the address of the creator of the contract and the number of transactions sent from that address (the so-called “nonce”). The payload used to create the contract will be converted to EVM bytes and executed. The executed output will be permanently stored as the contract code.
注解
在合约创建的过程中,它的代码还是空的。所以直到构造函数执行结束,你都不应该在其中调用合约自己函数。
一经创建,每笔交易都收取一定数量的 gas ,目的是限制执行交易所需要的工作量和为交易支付手续费。EVM 执行交易时,gas 将按特定规则逐渐耗尽。
Once created, a certain amount of gas is charged for each transaction, with the aim of limiting the amount of work required by the executing exchange and paying the transaction fees.
gas price 是交易发送者设置的一个值,发送者账户需要预付的手续费= 。如果交易执行后还有剩余, gas 会原路返还。
无论执行到什么位置,一旦 gas 被耗尽(比如降为负值),将会触发一个 out-of-gas 异常。当前调用帧(call frame)所做的所有状态修改都将被回滚。
Regardless of where it is executed, once gas is depleted (e.g. down to negative values), it triggers an out-of-gas anomaly. All state changes made at the current call frame are rolled back.
译者注:调用帧(call frame),指的是下文讲到的EVM的运行栈(stack)中当前操作所需要的若干元素。
Translator Note: Call frame refers to a number of elements that are required for the current operation in the EVM running pad (stack) described below.
每个账户有一块持久化内存区称为 存储 。 存储是将256位字映射到256位字的键值存储区。 在合约中枚举存储是不可能的,且读存储的相对开销很高,修改存储的开销甚至更高。合约只能读写存储区内属于自己的部分。
Each account has a sustainable memory area called
第二个内存区称为 内存 ,合约会试图为每一次消息调用获取一块被重新擦拭干净的内存实例。 内存是线性的,可按字节级寻址,但读的长度被限制为256位,而写的长度可以是8位或256位。当访问(无论是读还是写)之前从未访问过的内存字(word)时(无论是偏移到该字内的任何位置),内存将按字进行扩展(每个字是256位)。扩容也将消耗一定的gas。 随着内存使用量的增长,其费用也会增高(以平方级别)。
The second memory area, known as
EVM 不是基于寄存器的,而是基于栈的,因此所有的计算都在一个被称为 栈(stack) 的区域执行。 栈最大有1024个元素,每个元素长度是一个字(256位)。对栈的访问只限于其顶端,限制方式为:允许拷贝最顶端的16个元素中的一个到栈顶,或者是交换栈顶元素和下面16个元素中的一个。所有其他操作都只能取最顶的两个(或一个,或更多,取决于具体的操作)元素,运算后,把结果压入栈顶。当然可以把栈上的元素放到存储或内存中。但是无法只访问栈上指定深度的那个元素,除非先从栈顶移除其他元素。
The EVM is not based on a sender, but on a stack, so all calculations are performed in an area known as stack. The maximum number of elements is 1024, with each element length being a word (256). Access to the stack is limited to its top and is limited to allowing one of the 16 elements at the top of the copy to reach the top, or to exchange the top element and one of the 16 elements below. All other operations can take the top two elements (or one or more, depending on the particular operation) and, after calculation, to press the result onto the top. Of course, the elements on the stack can be placed in storage or memory. But it is not possible to access only the element at the depth specified on the top of the stack, unless other elements are removed from the top.
EVM的指令集量应尽量少,以最大限度地避免可能导致共识问题的错误实现。所有的指令都是针对"256位的字(word)"这个基本的数据类型来进行操作。具备常用的算术、位、逻辑和比较操作。也可以做到有条件和无条件跳转。此外,合约可以访问当前区块的相关属性,比如它的编号和时间戳。
The EVM command collection should be kept as low as possible in order to avoid errors that could lead to consensus issues. All instructions are directed at &quat; 256-digit word & quot; this basic data type. There are commonly used arithmetic, bit, logic, and comparison operations. There can also be conditional and unconditional jumps. Furthermore, the contract can access the properties associated with the current block, such as its numbering and time stamp.
合约可以通过消息调用的方式来调用其它合约或者发送以太币到非合约账户。消息调用和交易非常类似,它们都有一个源、目标、数据、以太币、gas和返回数据。事实上每个交易都由一个顶层消息调用组成,这个消息调用又可创建更多的消息调用。
Contracts can call other contracts by calling messages or sending them to non-contractual accounts. Message calls and transactions are very similar, and they all have a source, target, data, data, gas, and return data. In fact, each transaction is composed of a top-level call, which creates more information call.
合约可以决定在其内部的消息调用中,对于剩余的 gas ,应发送和保留多少。如果在内部消息调用时发生了out-of-gas异常(或其他任何异常),这将由一个被压入栈顶的错误值所指明。此时,只有与该内部消息调用一起发送的gas会被消耗掉。并且,Solidity中,发起调用的合约默认会触发一个手工的异常,以便异常可以从调用栈里“冒泡出来”。 如前文所述,被调用的合约(可以和调用者是同一个合约)会获得一块刚刚清空过的内存,并可以访问调用的payload——由被称为 calldata 的独立区域所提供的数据。调用执行结束后,返回数据将被存放在调用方预先分配好的一块内存中。 调用深度被 限制 为 1024 ,因此对于更加复杂的操作,我们应使用循环而不是递归。
The contract may determine how much it should be sent and retained for the remaining gas in its internal call. If an `out-of-gas anomaly (or any other anomaly) occurs at the time of the internal call, it will be indicated by an error value that has been crushed to the top of the stack. At this point, only the gass sent with the internal call will be consumed. And, in Solidity, the default of the contract initiating the call triggers a manual anomaly so that an anomaly can be “pluged out” from the switchboard.
有一种特殊类型的消息调用,被称为 委托调用(delegatecall) 。它和一般的消息调用的区别在于,目标地址的代码将在发起调用的合约的上下文中执行,并且 和 不变。 这意味着一个合约可以在运行时从另外一个地址动态加载代码。存储、当前地址和余额都指向发起调用的合约,只有代码是从被调用地址获取的。 这使得 Solidity 可以实现”库“能力:可复用的代码库可以放在一个合约的存储上,如用来实现复杂的数据结构的库。
A special type of message call, known as "delegatecall" . The difference between it and the usual message call is that the target address code will be executed in the context of the initiating contract and will remain unchanged. This means that a contract can be loaded dynamically from another address when it is running. Storage, current address, and balance point to the initiating contract, except that the code is obtained from the calling address. This enables Solidity to "capability": the reusable code library can be placed on a contract storage, such as the one used to achieve a complex data structure.
有一种特殊的可索引的数据结构,其存储的数据可以一路映射直到区块层级。这个特性被称为 日志(logs) ,Solidity用它来实现 事件(events) 。合约创建之后就无法访问日志数据,但是这些数据可以从区块链外高效的访问。因为部分日志数据被存储在 布隆过滤器(Bloom filter) 中,我们可以高效并且加密安全地搜索日志,所以那些没有下载整个区块链的网络节点(轻客户端)也可以找到这些日志。
There is a special indexable data structure, where stored data can be mapped all the way up to the block level. This feature is known as
合约甚至可以通过一个特殊的指令来创建其他合约(不是简单的调用零地址)。创建合约的调用 create calls 和普通消息调用的唯一区别在于,负载会被执行,执行的结果被存储为合约代码,调用者/创建者在栈上得到新合约的地址。
The contract can even create other contracts by a special command (not simply calling zero addresses). The only difference between creating a contract by calling createcalls and an ordinary message is that the load will be executed, the results of the execution will be stored as contract codes, and the caller/founder will get the address of the new contract on the pad.
合约代码从区块链上移除的唯一方式是合约在合约地址上的执行自毁操作 。合约账户上剩余的以太币会发送给指定的目标,然后其存储和代码从状态中被移除。
The only way the contract code can be removed from the block chain is for the contract to perform a self-destruct operation on the contract address. The remaining NT on the contract account will be sent to the specified target, and the storage and code will be removed from the status.
警告
尽管一个合约的代码中没有显式地调用 ,它仍然有可能通过 或 执行自毁操作。
注解
旧合约的删减可能会,也可能不会被以太坊的各种客户端程序实现。另外,归档节点可选择无限期保留合约存储和代码。
注解
目前, 外部账户 不能从状态中移除。
注册有任何问题请添加 微信:MVIP619 拉你进入群
打开微信扫一扫
添加客服
进入交流群
发表评论