(一)初步认识EVM字节码
(一)初步认识EVM字节码(二)状态变量的赋值(三)函数调用 前言 在开始之前,我们默认读者已经初步理解 EVM, 包括字节码、操作码、堆栈、内存、存储、calldata。理解 ABI,能够根据文档计算对应变量的 ABI,并且具有一定的编译基础。因此,如果阅读过程中觉得困难,请先阅读 EVM 的其他文章,如 初步理解以太坊虚拟机。 本文编译器版本采用 0.8.10,EVM 版本是 London。没有特殊说明的条件下,默认关闭编译优化。建议读者复现时采用相同的编译器和 EVM,避免不一样的结果,虽然一般而言小版本的变化区别不大。 合约创建 字节码和运行时字节码 我们首先部署一个空的合约 Empty.sol,观察合约部署的字节码。这里需要注意区分运行时代码和部署时代码,creation bytecode 在部署后被舍弃,RETURN 的运行时字节码写入区块链。 123456// SPDX-License-Identifier: GPL-3.0pragma solidity >=0.7.0 <0.9.0;contract Empty {} 在...
EVM的设计与原理
初步理解以太坊虚拟机以太坊的数据组织EVM的设计与原理 前言 在阅读这篇文章之前,请您先阅读初步理解以太坊虚拟机和以太坊的数据组织,它将会介绍 EVM 的基本知识,帮助您形成基本的认识。在开始之前,假设您已经掌握了上文中的基础,我们根据黄皮书进一步地补充理论基础。由于原始的黄皮书公式过多,不易阅读,可以参考按照论文重写后的版本。其次,本文使用的图片来自其他资料,会在参考资料部分注明。 非常推荐读者观看这个视频:EVM: From Solidity to byte code, memory and storage ,这是配套的 PDF。 它梳理源码到字节码的流程,演示操作码的变化,非常棒。如果读者通过前面提到的文章以及理解 EVM 的存储空间布局的话,这个视频可以为您提供字节码编写合约的基础:smirk_cat:.请善用 Remix IDE 的单步调试功能,可以通过实操,大大加深理解。 EVM 设计原理 以太坊可以抽象的分成两部分,一部分是状态,另外一部分是用于改变状态的...
初步理解以太坊虚拟机
初步理解以太坊虚拟机以太坊的数据组织EVM的设计与原理 体系结构 存储层 一般的客户端采用 LevelDB 数据库,而 OpenEthereum 采用了 RocksDB。LevelDB 是 Key-Value 的、基于 Log-Structured Merge Tree 的非关系数据库。例如 geth 的所有区块数据都是存储在 LevelDB 中,而 LevelDB 的实现在源代码的 ethdb 包内。 数据层 以太坊的数据层主要定义了数据结构、数据模型、哈希函数、签名算法等。以太坊采用独特的数据结构保护区块头和区块体,区块头含有交易的 Merkle 根哈希值,还有账户状态的 Merkle 根哈希值、日志的 Merkle 根哈希值。以太坊中 Merkle 根哈希值是采用 Merkle Patricia Tree 计算的。哈希函数使用 keccak256,数字签名采用 ECDSA。 网络层 以太坊节点通信采用的 p2p 协议是 DEVp2p,包含了 RLPx、Discv4 等子协议。RLPx 是安全的数据传输协议,采用 ECIES(Elliptic Curve...
以太坊的数据组织
初步理解以太坊虚拟机以太坊的数据组织EVM的设计与原理 这篇文章主要介绍以太坊的数据组织形式,构建以太坊各部分数据结构是如何组织的系统观。随后,我将会选取黄皮书中的核心设计思想,写得相对通俗易懂。各部分具体的数据结构,将会在后续的源码解读中给出。 概览 以太坊的区块由区块头和区块体构成,区块头存储元数据,通过区块哈希形成链式结构。区块体用于存储交易的集合和其他数据,大致结构如下: Trie Tree Trie Tree 被称作字典树,或者 前缀树 (prefix Tree),用于管理键值对类型的多叉树。字典树的 Key 不是直接保存在某一个节点,而是通过节点在树中的位置确定,类似于哈夫曼编码树。因此,可知子节点都有相同的前缀。只有叶子节点才存放 Value,从根节点到叶子节点形成的路径上的节点,按照顺序排列构成 Value 的 Key. 假如 节点 d 存储 Value,则 and 是它的 Key 总体如下: 根节点不包含字符,根节点外的所有节点都只包含一个字符。 从根节点到某个节点,路径上经过的的字符连起来,为该节点对应的 Key. 每个节点的 Key...
(八)合约的高级特性(完)
区块链基础(一)初步理解智能合约(二)代码结构和合约特性(三)控制结构(四)类型(五)字面量和内置单位、函数(六)应用二进制接口(七)特殊函数(八)合约的高级特性(完) 继承 继承的机制和 python 的非常相似,但是存在差异。一般而言使用过 C++, 基本已经掌握。 当合约继承其他的合约时,只会在区块链上生成一个合约,所有相关的合约都会编译进这个合约,调用机制和写在一个合约上一致。 继承时,全局变量无法覆盖,如果出现可见的同名变量会编译错误。通过例子来体会细节,重点理解语法,而不是程序逻辑。 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657// SPDX-License-Identifier: GPL-3.0pragma solidity >=0.7.0 <0.9.0;contract Owned { constructor() { owner =...
DeFi攻击事件研究
前言:本文只为了交流学习,为了快速学习,已有的写的较好的资料直接照抄,并且在参考中注明来源。介绍的都非常简略,但是读者可以根据参考链接得到详细的讲解。 汇总表格 发生时间 名字 类型 损失金额 简述原因 代码 txhash 2022 年 07 月 25 日 LPC BNB 约 45,715 美元 实际的账户余额在后续操作中变化了,但是变量 recipientBalance 没有再次更新,导致后续计算余额偏大。 0x0e970ed84424d8ea51f6460ce6105ab68441d4450a80bc8d749fdf01e504ed8c 2022 年 06 月 27 日 XCarnival NFT ETH,业务逻辑漏洞 约 380 万美元 未考虑抵押物被取出不能借款的业务逻辑,主要是 isWithdraw(bool) 未在 borrow...
(七)特殊函数
区块链基础(一)初步理解智能合约(二)代码结构和合约特性(三)控制结构(四)类型(五)字面量和内置单位、函数(六)应用二进制接口(七)特殊函数(八)合约的高级特性(完) 底层函数交互 特殊交互方式 call 是底层的调用(没有封装过),直接发送消息给合约。方式如下: 所有的参数,都会打包成一串 32 个字节,连续存放的序列。 若第一个参数是函数的签名(函数哈希之后的前 4 个字节),则第二、第三这些后面的参数是函数的参数。如:nameReg.call(bytes4(keccak256("fun(uint256)")), a); <address>.call(bytes memory) returns (bool, bytes memory) 用给定的合约发出低级 CALL 调用,返回成功状态及返回数据,发送所有可用 gas,也可以调节 gas。 123456789101112131415161718192021222324252627282930313233343536373839//...
(六)应用二进制接口
区块链基础(一)初步理解智能合约(二)代码结构和合约特性(三)控制结构(四)类型(五)字面量和内置单位、函数(六)应用二进制接口(七)特殊函数(八)合约的高级特性(完) 接口含义 在地址类型的介绍中提到了底层调用的 call 函数,这里将会介绍它的用法,以及和 ABI 函数的配合。 ABI 全名 Application Binary Interface,翻译为应用二进制接口。它定义了与合约交互的规范,因此底层函数 (如 call) 直接给合约发消息前,需要了解 ABI。 ABI 是由合约生成的,规定与合约交互方式的规则,它是一个接口,常被 web3 等库调用。熟悉 REST API 的读者应该能很快理解。 例如下面是智能合约: 12345678910111213141516171819202122232425262728293031323334353637383940// SPDX-License-Identifier: GPL-3.0pragma solidity >=0.7.0 <0.9.0;/** * @title Owner * @dev...
(五)字面量和内置单位、函数
区块链基础(一)初步理解智能合约(二)代码结构和合约特性(三)控制结构(四)类型(五)字面量和内置单位、函数(六)应用二进制接口(七)特殊函数(八)合约的高级特性(完) 字面常量 地址 地址的字面常量有 EIP-55 的标准(区分大写字母和小写字母来验证),只有经过校验后才能作为 address 变量。 有理数和整数 十进制的小数字面常量都会带一个.比如1. .1...
(四)类型
区块链基础(一)初步理解智能合约(二)代码结构和合约特性(三)控制结构(四)类型(五)字面量和内置单位、函数(六)应用二进制接口(七)特殊函数(八)合约的高级特性(完) Solidity 的值传递和引用传递有自己的规则,通过不同的存储域决定,后面详述。 默认值:Solidity 中不存在undefined或null,每种变量都有自己的默认值,一般是“零状态”。 运算符优先级 布尔类型 bool:常量值为true和false 整型 int / uint :分别表示有符号和无符号的不同位数的整型变量。 支持关键字 uint8 到 uint256 (无符号,从 8 位到 256 位)以及 int8 到 int256,以 8 位为步长递增。 uint 和 int 分别是 uint256 和 int256 的别名。 可以用type(x).min type(x).max来获取这个类型地最小值和最大值。 位运算 在二进制地补码上操作,特别的 ~int256(0)==...