第1章 一台全球计算机
以太坊 历史 以太坊 发展阶段 以太坊 特色第2章 账户是什么
以太坊 基础知识 Keystore 与私钥保存 以太坊 常用钱包 以太坊 EIP-55 账户地址第3章 交易是驱动力
以太坊 交易是驱动力 以太坊 交易发送 以太坊 交易方法 以太坊 交易生命周期 共识与工作量证明 矿工与挖矿奖励第4章 数据结构
以太坊 数据结构 以太坊 Radix树 以太坊 Merkle树 Merkle Patricia树 以太坊 RLP编码 以太坊 状态树 以太坊 交易树 以太坊 收据树 以太坊 区块第5章 构建私链
以太坊 安装geth 以太坊 启动私链 以太坊 接收挖矿奖励 以太坊 转账与收款第6章 部署智能合约
以太坊 部署智能合约 以太坊 什么是智能合约 以太坊 安装编译器 Solc 编译智能合约 智能合约发布准备 部署智能合约 调用智能合约第7章 以太坊虚拟机
以太坊虚拟机 虚拟机的执行结果 虚拟机的执行资源 合约调用合约 虚拟机的输入输出 Gas 花费与退回 虚拟机指令集第8章 Solidity 语法
Solidity 语法练习 Solidity 基础语法 Solidity 语法进阶 Solidity 高级语法 Solidity 安全第9章 Truffle 开发
Truffle 合约开发 编译、测试工具安装 Truffle 启动样例 Truffle ERC20合约 Truffle ERC20合约测试Truffle 冷知识
Truffle 冷知识 短地址攻击 比特币的区块 以太坊与比特币账户的区别 “不可能的三角”问题 ETHASH 挖矿算法第1章 一台全球计算机
以太坊 历史 以太坊 发展阶段 以太坊 特色第2章 账户是什么
以太坊 基础知识 Keystore 与私钥保存 以太坊 常用钱包 以太坊 EIP-55 账户地址第3章 交易是驱动力
以太坊 交易是驱动力 以太坊 交易发送 以太坊 交易方法 以太坊 交易生命周期 共识与工作量证明 矿工与挖矿奖励第4章 数据结构
以太坊 数据结构 以太坊 Radix树 以太坊 Merkle树 Merkle Patricia树 以太坊 RLP编码 以太坊 状态树 以太坊 交易树 以太坊 收据树 以太坊 区块第5章 构建私链
以太坊 安装geth 以太坊 启动私链 以太坊 接收挖矿奖励 以太坊 转账与收款第6章 部署智能合约
以太坊 部署智能合约 以太坊 什么是智能合约 以太坊 安装编译器 Solc 编译智能合约 智能合约发布准备 部署智能合约 调用智能合约第7章 以太坊虚拟机
以太坊虚拟机 虚拟机的执行结果 虚拟机的执行资源 合约调用合约 虚拟机的输入输出 Gas 花费与退回 虚拟机指令集第8章 Solidity 语法
Solidity 语法练习 Solidity 基础语法 Solidity 语法进阶 Solidity 高级语法 Solidity 安全第9章 Truffle 开发
Truffle 合约开发 编译、测试工具安装 Truffle 启动样例 Truffle ERC20合约 Truffle ERC20合约测试Truffle 冷知识
Truffle 冷知识 短地址攻击 比特币的区块 以太坊与比特币账户的区别 “不可能的三角”问题 ETHASH 挖矿算法虚拟机的执行资源
以太坊的虚拟机经常被拿来与x86台式机的结构作对比,它们有相同点也有很大的不同点。
相比于台式机或者手机,以太坊的虚拟机更加紧凑,资源更加匮乏。 它并不包含正常的CPU 所具备的硬件寄存器(Register),所以执行速度没有这么快。 它的执行宽度都是 256bit 的固定长度值,所以相对比较容易编程,它包含了存储、堆栈、内存三大存储机构。
下图显示了以太坊的虚拟机的执行资源。

以太坊虚拟机的执行资源
Storage 存储
存储里的值都是永久记录在区块链上的。存储在写和读取上都代价昂贵,如非必须,则数据不要存储在存储区。 存储区是全世界计算机都会同步到硬盘上的区块链的一部分,哪怕关机以后也被永久记录。 那么哪些值需要保存在这里呢?只有那些需要在程序执行后任然留存的数字才需要, 例如以太坊的 ERC20 智能合约追踪 token 持有者和 token 数量的关系,这个数据需要持久化保存到存储区。
存储区的数据都是 256bit 的键和值配对存储,如下图所示。如果查询时一个键对应的值不存在,则它读取的值为 0 。 存储区的读写操作都是以 256bit 为单位的,没有更小的操作空间。故而 uint8 和 uint256 在单值存储的情况下占用的空间相同,耗费的 Gas 也相同。
将 unit8 包裹进入 struct 结构体以后可以通过优化来节约空间位置,节省 gas 支出。

存储 Storage 示意图,索引和值都是256位的数据
Stack 堆栈
堆栈的花费和内存差不多,堆栈往往保存了执行过程的上下文,如下图所示。 堆栈有且仅有 1024 层深度,当我们执行递归调用过多的时候,堆栈就会击穿 1024 层,则代码执行失败。这在其他编程语言中也是相同的原理。
堆栈仅有高处的 16 层是可以被快速访问的,堆栈的宽度也是 256bit,也就是 32byte,一个 word 的长度,任何读写操作都是 256bit 为一个单位进行的。 编译器往往会将代码执行中的临时变量、变量地址放到堆栈上临时保存,变量地址可以进一步索引到内存 Memory 中。

堆栈 Stack 示意图,数据都是256bit进出堆栈
Memory 内存
内存在以太坊虚拟机中和真实计算机的内存概念相近:一旦虚拟机启动,内存就处在不断变化之中,承载了程序运行时的指令和数据的保存。 一旦虚拟机执行结束并关机,内存保存的数据就会灰飞烟灭。
内存的管理办法也是按照 256bit 为单位进行读取和写入, 如下图所示。写入时候也可以选择 8bit 为单位写入,因为内存的宽度是 8bit。内存的读取和写入都相对其他两种存储而言更便宜。
举例来说,读取和写入一个 256bit的值花费仅有 3Gas,是 Storage 存储区的写操作的万分之一多一点。

内存 Memory,合约执行完毕就会自动清空
下一章:合约调用合约
合约还能被合约调用吗?是的,可以。在以太坊中执行代码的一台虚拟机可以启动另一台虚拟机来执行部分指令。这两台虚拟机都将在一个挖矿节点上运行,形成多线程并行。这称之为“合约调用合约”。 常见的合约调用合约的 ...
AI 中文社