声明:此为使用网上多处资料整理而成,由于很多地方内容相同,已经分不清哪里是原创

一. 以太坊的区块结构


从上图可以看到,区块由两部分组成,分别是区块头(header)和区块体(body)两部分。

1. 区块头(header)

区块头存储了区块的元信息,用来对区块内容进行一些标识,校验,说明等。区块头里字段分为两部分区块头和区块体。

通用字段

    ParentHash: 父区块的哈希值Root:全局状态MPT树的根哈希,世界状态的哈希,这个全局状态树包含了以太坊网络中每一个账户的一组键值对,stateDB的RLP编码后的哈希值TxHash(transaction root hash):交易MPT树的根哈希,由本区块所有交易的交易哈希算出ReceptHash:收据MPT树的哈希Time:区块产生出来的Unix时间戳Number:区块号Bloom:布隆过滤器,快速定位日志是否在这个区块中。

公链场景

Coinbase:挖出这个块的矿工地址,因为挖出块所奖励的ETH就会发放到这个地址。
Difficulty:当前工作量证明(Pow)算法的复杂度。
GasLimit: 每个区块Gas的消耗上线。
GasUsed:当前区块所有交易使用的Gas之和。
MixDigest: 挖矿得到的Pow算法证明的摘要,也就是挖矿的工作量证明。
nonce:挖矿找到的满足条件的值。
UncleHash:叔块是和以太坊的共识算法相关。
一般而言一个类以太坊的联盟链是需要上面介绍的通用字段的,但是也不绝对,还可能与选择的共识算法,隐私保护策略,设计偏好有关。

每个块都有一个「header」,它存储三个不同Merkle树结构根节点的哈希,包括:

  • 状态树
  • 交易树
  • 收据树

它允许轻客户端轻松地进行并核实以下类型的查询答案:

这笔交易被包含在特定的区块中了么?      --交易树(transaction tree)
告诉我这个地址在过去30天中,发出X类型事件的所有实例(例如,一个众筹合约完成了它的目标) --收据树(receipt tree)
目前我的账户余额是多少?            --状态树(state tree)
这个账户是否存在?                 --状态树(state tree)
假装在这个合约中运行这笔交易,它的输出会是什么?   --状态树(state tree)

第一种是由交易树(transaction tree)来处理的;第三和第四种则是由状态树(state tree)负责处理,第二种则由收据树(receipt tree)处理。计算前四个查询任务是相当简单的。服务器简单地找到对象,获取梅克尔分支,并通过分支来回复轻客户端。

第五种查询任务同样也是由状态树处理,但它的计算方式会比较复杂。这里,我们需要构建下我们称之为梅克尔状态转变的证明(Merkle state transition proof)。从本质上来讲,这样的证明也就是在说“如果你在根S的状态树上运行交易T,其结果状态树将是根为S’,log为L,输出为O” (“输出”作为存在于以太坊的一种概念,因为每一笔交易都是一个函数调用,它在理论上并不是必要的)。

为了推断这个证明,服务器在本地创建了一个假的区块,将状态设为 S,并假装是一个轻客户端,同时请求这笔交易。也就是说,如果请求这笔交易的过程,需要客户端确定一个账户的余额,这个轻客户端会发出一个余额疑问。如果这个轻客户端需要检查存储在一个特定合约的特定项目,该轻客户端会对此发出针对查询。服务器会正确地“回应”它所有的查询,但服务器也会跟踪它所有发回的数据。然后,服务器会把综合数据发送给客户端。客户端会进行相同的步骤,但会使用它的数据库所提供的证明。如果它的结果和服务器要求的是相同的,那客户端就接受证明。

1)状态树

全局状态树包含了以太坊网络中每一个账户的一组键值对,每次生成一个新的区块,以太坊状态发生改变后并不会去修改原来的MPT树,而是会新建一些分支,如下图所示;

全局状态树的Key是一个 160 位的标识符(以太坊账户的地址),全局状态树中的 “值” 是通过编码以太坊账户中的如下细节来得到的(使用RLP的方法):

  • nonce 值
  • 余额
  • 存储前缀树根节点哈希
  • 代码哈希

    存储树是智能合约数据存储的位置,每一个以太坊账户都有自己的存储树

优势

  • 当一个账户的余额发生改变后,对应路径的哈希也发生了变化,然后自底而上的更新对应路径上的哈希值,直至Satet Root,这样可以计算最少的哈希次数。
  • 以太坊中的全节点维护的是增量的MPT状态树,因为每次一个区块对世界状态的修改都只是很小的一部分,增量修改既有利于区块回滚,又可以节约开销。
  • 在以太坊中区块临时分叉很普遍,但是由于以太坊智能合约的复杂性,如果不记录原始状态,很难根据合约代码回滚状态。

2)收据树

以太坊在智能合约执行时会产生一个交易回执(Receipt)记录了此笔交易的执行结果,交易信息和区块信息。


当查询轻节点查询通过布隆过滤器找到交易后,为了避免误识,还会再次查询回执来避免误识。

3)交易树

交易树的作用是提供了交易的默克尔证明,证明某个交易被打包到某个区块里,轻节点不用存储区块体仅根据提供的默克尔证明就可以快速判断交易是否已经被打包。

4)三颗树的差异

交易树和收据树只依赖当前的区块,而状态树是把链上所有状态都包含进去,交易树和收据树是独立的,状态树会共享树的节点。

为什么状态树要包含所有链上所有的状态呢?

举个例子,当一笔转账操作的发起时,需要判断发起账户是否有足够的ETH来完成这笔转账,这个时候要通过查找状态树查看对应账户的状态,但是如果为了节约空间,只保存了当前区块账户的状态,就需要逐块查找,非常影响性能,甚至这个转账交易的发起者都不存在,是一个恶意操作。

2. 区块体(body)

区块体包括这个区块打包的所有交易,在一些链的设计中,并不像以太坊区分header和body,而是整合在一起。

3. 区块存储

以太坊在存储区块的时候,区块头和区块体其实是分开存储的,其实也很容易理解,分开存储可以提供更多的灵活性,比如不用保存全部区块数据的轻节点。

区块头存储,以太坊通过如下方式将区块头转换成键值对存储在LevelDB中;

headerPrefix + num + hash  -> rlp(header)
Tips: num是以大端序的形式转换成bytes的,其中headerPrefix的值是 []byte("h")

区块体存储

bodyPrefix + num + hash -> rlp(block)
Tips: num是以大端序的形式转换成bytes的,其中bodyPrefix的值是[]byte("b")

4. 潜在问题

假设在一个联盟链的场景下,采用了BFT类的算法,有一个重量级的业务跑在上面,日积月累产生了大量的数据,是否会出现LevelDB的读写性能大幅下降拖慢系统的响应速度?单机存储无法满足需要?存储了大量的不会使用的历史数据?

在联盟链的场景下,由于共识速度的提升,导致出块速度也大幅提升,原本在公链场景下不存在的区块写入瓶颈,现在反而成了拖慢系统运行速度的重要因素了。

观察一下区块数据的存储就可以发现下面的这些特点;

  • 区块数据只会增加;
  • 无需对历史区块进行修改;
  • 无需对区块数据进行复杂操作,比如聚合,运算等;

归纳一下就是顺序写,随机读和迭代(Iterator),针对这些特点Hyperledger Fabric设计了基于文件的存储方式,在Fabric中区块数据是以一个个文件的形式存在。

chains|----mychannel|----|----blockfile_000000
index|----000001.log|----CURRENT|----LOCK|----LOG|----MANIFEST-000000

其中blockfile_000000是区块数据,index则是索引游标等元信息,这种方式速度很快,方便做数据归档,也可以避免像LevelDB等数据库数据越写越慢的问题,主流联盟链都是采用类似的方案。

以太坊的帐户

以太坊的全球「共享状态」是由许多账户组成的,它们能够通过一个消息传递框架相互通信。每个帐户都有一个与它关联的状态和一个20字节的地址。以太坊的地址是一个160位比特的标识符,用于识别帐户。

以太坊有两种账户类型:

  • 外部帐户由私人密钥控制,没有与之相关的代码。
  • 合约账户由其合约代码控制,并具有与其相关的代码。

以太坊中的哈希

无论是比特币还是以太坊中,都采用了SHA(Security Hash Algorithm)哈希函数进行加密,在比特币中采用了SHA256的哈希函数,而在以太坊中,使用SHA3函数(Keccak函数)。它们的区别在于,SHA256属于SHA-2,即第2代哈希函数,而SHA3属于第3代哈希函数,第1代哈希函数已经被破解,已经不再适用于加密了。包括我们之前使用的MD5加密函数,也已经被发现可以制造碰撞,已经废弃了。2015年8月5日,美国标准技术协会(NIST)正式发布了SHA3,以其作为最新的一代标准加密函数。值得说明的是,比特币中的SHA256目前也没有被发现可以人为制造碰撞的方法。经过SHA256加密后可以得到长度为256bits的哈希值,比特币中一个用户的账户地址,就是将其公钥输入到SHA256算法中得到256bits的输出得到。而以太坊中,经过SHA3加密后得到160bits的输出。

以太坊中的序列化方法RLP

RLP(Recursive Length Prefix)可以将任意的数据编码成二进制byte的数组,即[]byte的形式。同时已知数据的RLP编码结果,可以求出其原来的形式。RLP在以太坊中作用主要有如下几个:

1.对结构体数据进行编码
2.将特殊的数据类型(string,floats等)编码为更高级的协议

RLP是以太坊中对数据进行编码的主要手段。以太坊要用到SHA3函数的地方,首先对该数据进行RLP编码,随后对RLP编码后的数据进行SHA3运算。因此以太坊中的SHA3计算是下列方式。更加详细的内容可以参见[RLP]。(https://github.com/ethereum/wiki/wiki/RLP)

encode(data)=SHA3(RLP(data))encode(data) = SHA3(RLP(data))encode(data)=SHA3(RLP(data))

帐户状态

无论帐户是哪种类型,帐户状态都由以下四个部分组成。

  • nonce:如果帐户是一个外部帐户,这个数字代表从帐户地址发送的交易数量。如果帐户是一个合约帐户,nonce是帐户创建的合约数量。
  • balance:这个地址拥有的Wei(以太坊货币单位)数量,每个以太币有1e+18 Wei。
  • storageRoot :一个Merkle Patricia树根节点的哈希,它对帐户的存储内容的哈希值进行编码,并默认为空。
  • codeHash:EVM(以太坊虚拟机)的哈希值代码。 对于合约帐户,这是一个被哈希后并存储为codeHash的代码。对于外部帐户,codeHash字段是空字符串的哈希。

以太坊基本数据结构分析相关推荐

  1. [以太坊源代码分析]III. 挖矿和共识算法的奥秘

    本系列的前两篇分别介绍了以太坊的基本概念,基本环节-交易,区块.区块链的存储方式等,这篇打算介绍一下"挖矿"得到新区块的整个过程,以及不同共识算法的实现细节. 1.待挖掘区块需要组 ...

  2. go-ethereum-code-analysis 以太坊源码分析

    分析go-ethereum的过程,我希望从依赖比较少的底层技术组件开始,慢慢深入到核心逻辑. 目录 go-ethereum代码阅读环境搭建 以太坊黄皮书 符号索引 rlp源码解析 trie源码分析 e ...

  3. 以太坊解析之二——POA共识过程与一些可能的修改方案

    以太坊解析之二--POA共识过程 原始版本创建于2021-05-27 文章目录 以太坊解析之二--POA共识过程 前言 一.工作流程 详细解析 二.详细过程 1.启动 2.同步 3.总结 4.一些其他 ...

  4. 以太坊RLP机制分析

    目录 1 RLP 定义 2 RLP 编码规则 3 RLP 编码实例 4 RLP 分析 1 RLP 定义 RLP,即 Recursive Length Prefix, 递归长度前缀编码,是以太坊数据序列 ...

  5. Windows搭建以太坊的私有链环境

    Windows搭建以太坊的私有链环境 1.下载Geth.exe 运行文件,并安装 https://github.com/ethereum/go-ethereum/releases/ 下载后,只有一个G ...

  6. 以太坊区块链Ethereum开发资料汇总

    2019独角兽企业重金招聘Python工程师标准>>> 基本概念介绍 :国内介绍区块链比较详细的资料 终于把区块链的技术与应用讲清楚了 http://business.sohu.co ...

  7. 想挖矿?不如先学习一下以太坊

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 许多使用点对点协议且基于区块链的项目在性能和吞吐量上夸大其辞.在研发阶段,这些项目已经出现了一些创新,但是一旦这些协议运 ...

  8. 以太坊挖矿源码:clique算法

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. clique 以太坊的官方共识算法是ethash算法,这在前文已经有了详细的分析: 它是基于POW的共识机制的,矿工需要 ...

  9. 深入浅出谈以太坊智能合约

    链客,专为开发者而生,有问必答! 此文章来自区块链技术社区,未经允许拒绝转载. 1什么是合约? 合约是代码(它的功能)和数据(它的状态)的集合,存在于以太坊区块链的特定地址. 合约账户能够在彼此之间传 ...

最新文章

  1. MVC使用Flash来显示图片
  2. 你有哪些 Deep learning(RNN、CNN)调参的经验?
  3. Apache Doris在美团外卖数仓中的应用实践
  4. (转载)(官方)UE4--图像编程----Parallel Rendering Overview
  5. identifier starts immediately after numeric literal
  6. 第三章 笔记本电脑案例
  7. HDU 1175 连连看(BFS)
  8. SQL Server数据挖掘简介
  9. String 是值类型还是引用类型
  10. 使用Hystrix守护应用(1)
  11. 蓝桥杯2019年第十届C/C++国赛B组 题B-质数拆分(素数筛选+01背包问题)
  12. 关于 System.getProperty
  13. Jenkins自动化构建Gitee项目
  14. 物联网时代,面临的几种安全威胁
  15. 计算机管理员权限设置在哪里设置方法,计算机管理员权限在哪里设置 电脑系统如何设置管理员权限...
  16. 电子元器件篇---三极管
  17. Oracle性能优化 以及 库缓存命中率及等待事件
  18. 阿里云天池大数据:【入门】精灵宝可梦数据集分析
  19. Godaddy无缝切换SSL,无需续费可省12美元
  20. WWDC22:“花里胡哨”的苹果又会给我们带来什么惊喜呢?

热门文章

  1. JAVA 进行图片中文字识别(准确度高)!!!
  2. rbegin()函数与rend()函数。
  3. python中字符型用什么表示_「小白学Python」Python中最常用的数据类型:字符串
  4. ubuntu18.04安装fcitx输入法
  5. 2014年4月23日
  6. JavaWeb使用过滤器实现自动登录功能
  7. node 写爬虫,原来这么简单
  8. DS哈希查找--Trie树
  9. TCP ISN、三次握手、四次挥手
  10. python计算机视觉编程——基于BOF的图像检索(附代码)