主页 > imtoken钱包苹果 > 以太坊和智能合约开发中的相关概念

以太坊和智能合约开发中的相关概念

imtoken钱包苹果 2023-03-11 07:49:06

本文让你了解以太坊中的几个重要概念,有助于你理解智能合约,包括它们的执行过程,以及开发智能合约时Solidity语言的相关概念

以太坊虚拟机 (EVM) 是以太坊中智能合约的运行时环境。 它不仅是沙盒化的,而且实际上是完全隔离的,这意味着在 EVM 内运行的代码无法接触网络、文件系统或其他进程。 即使是智能合约,与其他智能合约的联系也很有限。

帐户

以太坊中有两种类型的账户,它们共享相同的地址空间。 外部账户,由公私密钥对(人)控制。 合约账户,此类账户由账户中存储的代码控制。

外部账户的地址由公钥确定,而合约账户的地址是在创建合约时确定的(这个地址是根据合约创建者的地址和该地址发送的交易数量计算的,以及地址发送的交易数量也称为“nonce”)

合约账户存储代码,外部账户不存储代码,除此之外,两类账户对于 EVM 是相同的。

每个账户都有一个键值对形式的持久化存储。 key和value的长度都是256bit以太坊合约代码长度,名字是storage。

此外,每个账户都有一个以太币余额(以“Wei”为单位),可以通过向其发送以太币交易来更改。

贸易

交易是一条消息,从一个账户发送到另一个账户(可以是同一个账户或零账户,见下文)。 交易可以包含二进制数据(有效载荷)和以太币。

如果目标帐户包含代码,则执行该代码,并且有效负载是输入数据。

如果目标账户是零账户(账户地址为0),交易将创建一个新合约。 如上所述,这个合约地址不是零地址,而是根据合约创建者的地址和这个地址发送的交易数量(称为nonce)计算得出的。 合约创建交易的有效负载作为 EVM 字节码执行。 执行的输出作为合约代码永久存储。 这意味着,为了创建合约,您不需要向合约发送真实的合约代码,而是发送返回真实代码的代码。

气体

以太坊上的每笔交易都会收取一定数量的天然气。 gas 的目的是在支付执行费用的同时限制执行交易所需的工作量。 当EVM执行一笔交易时,gas会按照一定的规则逐渐消耗。

gas price(gas price, in Ether)由交易创建者设定,发送账户需要预付交易费=gas price * gas amount。 如果执行后还有gas剩余,gas会返还给发送账户。

无论在哪里执行,一旦gas耗尽(比如下降到负值),都会触发out-of-gas异常。 当前调用框架所做的所有状态修改都将回滚。

存储器、主存储器和堆栈

每个帐户都有一个称为存储的持久内存区域。 它的格式是key-value,key和value的长度都是256位。 在合约中,无法遍历账户的存储。 与其他两者相比,存储读取操作的开销相对较大,而修改存储的开销更大。 合约只能读写自己的存储。

第二个内存区域称为主内存。 每次合约执行消息调用时,都会有一个新的、清理过的主内存。 主存可以按字节粒度寻址,但读写粒度为32字节(256位)。 操作主内存的开销随着它的增长而增长(平方尺度)。

EVM 不是基于寄存器的,而是基于堆栈的虚拟机。 因此所有的计算都在一个称为堆栈的区域中进行。 堆栈最多有1024个元素,每个元素256位。 通过允许将顶部 16 个元素之一复制到堆栈顶部,或将堆栈的顶部元素与以下 16 个元素之一交换,对堆栈的访问仅限于其顶部。 所有其他操作只能取栈顶的两个(或一个,或多个,取决于具体操作)元素并将结果压入栈顶。 当然,你可以把栈上的元素放入存储器或主存中。 但是不可能只访问栈上指定深度的元素。 在此之前,必须从堆栈中删除指定深度以上的所有元素。

指令系统

EVM 的指令集有意保持在最小尺寸,以尽可能避免可能导致共识问题的不正确实现。 所有指令都对 256 位的基本数据类型进行操作。 具有常用的算术、位、逻辑和比较运算。 也可以进行有条件和无条件的跳转。 此外,合约可以访问当前区块的相关属性,例如它的编号和时间戳。

留言电话

合约可以通过消息调用调用其他合约或发送以太币给非合约账户。 消息调用与交易非常相似,它们都有源、目的地、数据有效负载、以太币、gas 和返回数据。 实际上,每笔交易都可以看作是一次顶层的消息调用,进而产生更多的消息调用。

一份合约可以决定剩余gas的分配。 例如内部消息调用使用了多少gas,或者预留了多少gas。 如果在内部消息调用期间发生 out-of-gas 异常(或其他异常),将通知合约并将错误代码压入堆栈。 这种情况只是内部消息调用的gas耗尽。 在 solidity 中,这种情况下的调用合约默认会触发人为异常。 此异常将打印出调用堆栈。

如前所述,被调用合约(以及调用合约)将拥有新的主内存并可以访问调用有效负载。 呼叫有效载荷存储在称为呼叫数据的单独区域中。 调用执行后,返回的数据会存放在调用者预先分配的一块内存中。

调用层数限制为1024,所以对于更复杂的操作,我们应该使用循环而不是递归。

代码调用和库

有一种特殊类型的消息调用称为调用代码。 它与消息调用几乎完全相同,只是从目标地址加载的代码将在调用合约的上下文中运行。

这意味着合约可以在运行时从另一个地址动态加载代码。 存储、当前地址和余额都指向调用合约,只有代码是从被调用地址中获取的。

这允许 Solidity 实现“库”。 可重用的库代码可以应用于合约的存储,可以用来实现复杂的数据结构。

日志

在块级别,可以使用特殊的可索引数据结构来存储数据。 此功能称为日志记录,Solidity 使用它来实现事件。 合约创建后,无法访问日志数据,但可以从区块链外部高效访问数据。 因为部分日志数据存储在布隆过滤器中以太坊合约代码长度,我们可以高效安全地搜索日志,所以那些没有下载整个区块链的网络节点(轻客户端)也可以找到这些日志。

创建

合约甚至可以通过特殊命令创建其他合约(而不是简单地调用零地址)。 创建合约的调用与普通消息调用的区别在于,payload 数据执行的结果被视为代码,调用者/创建者在堆栈上获得新合约的地址。

自我毁灭

只有当某个地址的合约自毁时,合约代码才会从区块链中移除。 合约地址上剩余的以太币被发送到指定的目的地,然后它的存储和代码被移除。