在以太坊中,有三棵树的说法,分别是状态树、收据树和交易树。了解了这三棵树,就弄清楚了以太坊的基础数据结构设计。 而以太坊实现的是一个"平台性"的应用,其复杂性必然较高。因此,其内部数据结构设计也存在一定复杂度。对此,ETH数据结构篇将花费较多篇幅进行编写。
3.1 引入
首先,我们要实现从账户地址到账户状态的映射。在以太坊中,账户地址为160位,表示为40个16进制数。状态包含了余额(balance)、交易次数(nonce),合约账户中还包含了code(代码)、存储(stroge)。
直观地来看,其本质上为Key-value键值对,所以直观想法便用哈希表实现。若不考虑哈希碰撞,查询直接为常数级别的查询效率。 但采用哈希表,难以提供Merkle proof。Merkel proof用来证明tree里面有什么,使用Merkle Tree的另一个目的是使各个节点的状态一致。
3.2 思考如何组织账户的数据结构
我们能否像BTC中,将哈希表的内容组织为Merkle Tree?这里我个人的理解是,把哈希表中的键值对就像交易的内容一样放在叶子节点。 比如你和一个人要签合同,希望他能证明一下他有多少钱,证明账户余额。一种方法是把哈希表组成一个Merkle tree, 算出一个根哈希值,放在区块头中公布出去,根哈希值是正确的就能保证底下的树没用被篡改。但当新区块发布,哈希表内容会改变,再次将所有的账户状态组织为新的Merkle Tree?如果这样,每当产生新区块(ETH中新区块产生时间为10s左右),都要重新组织Merkle Tree,注意是对账户余额的状态做一个Merkle Tree,账户可以是无限的,所以这不现实。
那为什么比特币系统就直接用了Merkle Tree?比特币系统中是对一个区块中的交易内容进行MT,不是整个账户的余额,区块包含上限为4000个交易左右,所以Merkle Tree不是无限增大的。并且每个区块里的交易信息大多数与上一个区块不一样,所以每个区块建立一个Merkel Tree是正常的,但是在ETH中,账户余额发生变化的仅仅为很少一部分数据,我们每次重新构建Merkle Tree代价很大。
那我们不要哈希表了,直接使用Merkle Tree,每次修改只需要修改其中一部分即可,这个可以吗?这里我个人的理解是,把一个账户地址和其所对应的状态直接放在叶子节点上。 但是,Merkle Tree并未提供一个高效的查找和更新的方案。此外,将所有账户构建为一个大的Merkle Tree,必须进行排序(Sorted Merkle Tree),因为账户如果散乱放在叶节点上,那构建的Merkle Tree不唯一,那不利于全节点的状态一致性。但是BTC中为什么不用排序,因为每个挖矿的节点打包交易的顺序确实不一样,但是大家最终会同步获得记账权的节点的块信息,当然就不需要排序。如果以太坊也像比特币一样把账户的状态每次在本地组装成一个Merkle Tree放在区块中然后再发布出去,首先这样的Merkle Tree的占用量很大,其次每次就修改很少的一部分账户余额,但还要把所有的账户状态建立树再打包没必要。
那么经过排序,使用Sorted Merkle Tree可以吗? 新增账户,由于其地址随机,插入Merkle Tree时候很大可能在Tree中间,发现其必须进行重构。所以Sorted Merkle Tree插入、删除(实际上可以不删除)的代价太大。
既然哈希表和 Merkle Tree都不可以,那么我们看一下实际中以太坊采取的数据结构:MPT。
注意:BTC系统中,虽然每个节点构建的Merkle Tree不一致(不排序),但最终是获得记账权的节点的Merkle Tree才是有效的。
3.3 一个简单的数据结构——trie(字典树、前缀树)
如下为一个通过5个单词组成的trie数据结构(只画出key,未画出value)

特点:
trie中每个节点的最大分支数目取决于Key值中每个元素的取值范围(图例中最多26个英文字母分叉+一个结束标志位)。在以太坊中地址表示成40位16进制,16再加上一个结束标志位,一共17个分支。
trie查找效率取决于key的长度,键值越长查找访问的内存次数就要更多。在以太坊中,地址长度为40个16进制的数,key值固定是40。(以太坊的地址是公钥取哈希截取后面一半,得到160位的地址。)
理论上使用哈希表可能会出现哈希碰撞,意思是两个地址可能不一样但映射到了同一个地方,而trie上面不会发生碰撞。
给定输入,无论如何顺序插入,构造的trie都是一样的。
更新操作局部性较好。
那么trie有缺点吗? 它的缺点是存储浪费。很多节点只存储一个key,但其“儿子”只有一个,出现一脉单传的情况,过于浪费,对于一些节点需要进行合并。因此,为了解决这一问题,我们引入Patricia tree/trie。
3.4 Patricia trie(Patricia tree)
Patricia trie就是进行了路径压缩的trie。如上图例子,进行路径压缩后如下图所示:

需要注意的是,如果新插入单词,原本压缩的路径可能需要扩展开来。那么,需要考虑什么情况下路径压缩效果较好?树中插入的键值分布较为稀疏的情况下,可见路径压缩效果较好。比如有几个单词很长的时候。

那在以太坊系统中,路径是否稀疏呢?160位的地址存在2^160 种,该数实际上已经非常大了,和账户数目相比,可以认为地址这一键值非常稀疏。为什么要这么稀疏呢?防止账户碰撞(比地球爆炸的概率还要小)。 因此,我们可以在以太坊账户管理种使用Patricia tree这一数据结构!但实际上,在以太坊种使用的并非简单的PT(Patricia tree),而是MPT(Merkle Patricia tree)。 把普通指针换成哈希指针。
3.5 Merkle Tree 和 Binary Tree
区块链和链表的区别在于区块链使用哈希指针,链表使用普通指针。 同样,Merkle Tree 相比 Binary Tree,也是普通指针换成了哈希指针。
所以,以太坊系统中可如此,将所有账户组织为一个经过路径压缩和排序的Merkle Tree,其根哈希值存储于block header中。
BTC系统中只有一个交易组成的Merkle Tree,而以太坊中有三个(三棵树)。 也就是说,在以太坊的block header中,存在有三个根哈希值。
根哈希值的用处:
防止篡改。
提供Merkle proof,可以证明账户余额,轻节点可以进行验证。
证明某个账户是否存在,例如你想向这个账户转一笔钱,想先知道这个账户是否在全节点中存在。如果存在,就把这个分支作为Merkle Proof发过去。
以太坊用的不是原生版的MPT(Merkle Patricia tree)用的是modified MPT。
3.6 Modified MPT (Modified Merkle Patricia tree)
下图为以太坊中使用的MPT结构示意图。右上角表示四个账户(为了直观,显示较少)和其状态(只显示账户余额)。(需要注意这里的指针都是哈希指针)

Extension Node: 如果这个节点出现了路径压缩就会是Extension Node。
nibble:十六进制数。
每次发布新区块,状态树中部分节点状态会改变。但改变并非在原地修改,而是新建一些分支,保留原本状态。如下图中,仅仅有新发生改变的节点才需要修改,其他未修改节点直接指向前一个区块中的对应节点。

所以,系统中全节点并非维护一棵MPT,而是每次发布新区块都要新建MPT。只不过大部分节点共享,只有少数发生变化的节点要新建分支。
为什么要保存原本状态?为何不直接修改? 为了便于回滚(roll back)。如下1中产生分叉,而后上面节点胜出,变为2中状态。那么,下面节点中状态的修改便需要进行回滚。因此,需要维护这些历史记录。不想比特币简单脚本,如果要发生回滚只需要对账户重新加减,但以太坊中有智能合约,无法轻易的对代码的结果产生回滚。
3.7 通过代码看以太坊中的数据结构
1. block header中的数据结构

ParentHash:前一个区块的块头的哈希值。
Root:状态树的根哈希值。
MixDigest:是根据Nonce经过哈希运算算出来的一个值
2. 区块结构

3. 区块在网上真正发布时的信息

最后说明 状态树中保存Key-value对,key就是地址,而value状态通过RLP(Recursive Length Prefix,一种进行序列化的方法)编码序列号之后再进行存储。
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
以太坊价格分析表明横盘整理,偏向中性。价格从前一交易日的高点1,791美元回落后正在盘整。但是,有趣的是,多头在1,680美元附近持有重要支撑。多头在1,700美元的心理水平附近聚集动能,并准备在接下来的几个交易日推向1,800美元。以太坊价格显示出盘整迹象,因为它形成了多个连续的顶部形态。这种回撤可能是第二大加密货币下一轮上涨的基石。以太坊连续第二个交易日走低。过去10天,价格在1,590-1,760美元的短期区间内盘整。每日烛台高于1,800美元将维持ETH的进一步上涨。ETH价格走低日线图上,以太坊价格在上升趋势线附近获得一轮支撑。来自879.80美元低点的看涨趋势线为ETH买家提供了支
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
文章目录1.任务背景2.任务目标3.相关知识点4.任务实操4.1安装配置JDK4.2启动FISCOBCOS4.3下载解压WeBASE-Front4.4拷贝sdk证书文件4.5启动节点4.6访问节点4.7检查运行状态5.任务总结1.任务背景FISCOBCOS其实是有控制台管理工具,用来对区块链系统进行各种管理操作。但是对于初学者来说,还是可视化界面更友好,本节就来介绍WeBASE管理平台,这是一款微众银行开源的自研区块链中间件平台,可以降低区块链使用的门槛,大幅提高区块链应用的开发效率。微众银行是腾讯牵头设立的民营银行,在国内民营银行里还是比较出名的。微众银行参与FISCOBCOS生态建设,一定
当音乐碰上区块链技术,会擦出怎样的火花?或许周杰伦已经给了我们答案。8月29日下午,B站独家首发周杰伦限定珍藏Demo独家访谈VCR,周杰伦在VCR里分享了《晴天》《青花瓷》《搁浅》《爱在西元前》四首经典歌曲Demo背后的创作故事,并首次公布18年前未发布的神秘作品《纽约地铁》的Demo。在VCR中,方文山和杰威尔音乐提及到“多亏了区块链技术,现在我们可以将这些Demos,变成独一无二具有收藏价值的艺术品,这些Demos可以在薄盒(国内数藏平台)上听到。”如何将音乐与区块链技术相结合,薄盒方面称:“薄盒作为区块链技术服务方,打破传统对于区块链技术只能作为数字收藏的理解。聚焦于区块链技术赋能,在
写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c
TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是
应用将在Heroku上运行依赖包括回形针哈姆指南针设计aws-s3支持或反对的理由?对其他版本的ruby有什么建议吗?更新Heroku目前不支持1.9.2,但预计很快会基于thispost.Rails3.0正式支持1.9.2(但不支持1.9.1),所以我决定继续使用它。更新Heroku在其beta堆栈上支持1.9.2。 最佳答案 我会说是的。当您准备好推出您的应用程序时(2-3个月?),应该解决越来越多的兼容性问题。此外,如果您遇到任何问题,您可以提交补丁并为更快的1.9.2兼容性做出贡献!;)但是为了回答您的问题,考虑到您要使
TCP是面向连接的协议,连接的建立和释放是每一次面向连接的通信中必不可少的过程。TCP连接的管理就是使连接的建立和释放都能正常地进行。三次握手TCP连接的建立—三次握手建立TCP连接①若主机A中运行了一个客户进程,当它需要主机B的服务时,就发起TCP连接请求,并在所发送的分段中用SYN=1表示连接请求,并产生一个随机发送序号x,如果连接成功,A将以x作为其发送序号的初始值:seq=x。主机B收到A的连接请求报文,就完成了第一次握手。客户端发送SYN=1表示连接请求客户端发送一个随机发送序号x,如果连接成功,A将以x作为其发送序号的初始值:seq=x②主机B如果同意建立连接,则向主机A发送确认报
似乎Capistrano曾经有anextensivefiletransferpackage.但是在3.0版本重写后好像没有了。知道是否还有其他方法可以将文件传输到服务器/从服务器传输文件吗? 最佳答案 下载:desc"downloadfoobar.txtintolocal_dir/"task:foobardodownload!"some_remote_path/foobar.txt","local_dir/"end我知道这从Cap3.2.1开始有效,因为我现在正在使用它。 关于ruby-