01.以太坊整体架构
以太坊是一个区块链应用平台。
分为三层:
- 底层服务
- 核心层
- 顶层应用
02.区块
-
区块链是比特币使用的底层技术架构。
-
他本身是一串连续的数据区块,区块之间的连接指针是区块头散列指针,他们是使用密码学散列算法生成的。
-
区块本质上就是一个数据包,比特币的交易记录会保存在区块中,大约每10分钟生成一个新的区块。
-
所谓区块:可以定义为记录一段时间内发生的交易和状态的结果的数据结构。是对当前账本状态的一次共识。
-
比特币的每个数据区块一般包含区块头(Header)和区块体(Body)两部分。
- 区块头封装了前一个区块的散列值(Prev_Hash),时间戳(Timestamp),随机数(Nonce),Merkle树的根值(Tx_Root)和当前区块的散列值等信息。
- 区块体中则主要包含交易技术和交易详情。
-
-
每笔交易都被永久的记录在区块中,任何人都可以查询。交易是通过Merkle树的数据结果记录的。其中没仪表交易都包含了数字签名,如此可以保证每一笔交易都不伪造,不能篡改。所有的交易过程都将通过Merkle树的hash过程生成一个唯一的Tx-Root记录到区块中。
-
用户在验证区块的有效性时,只需根据Merkle树的Hash方法计算出根值并且与区块中Tx_Root进行比较,即可验证真伪,若相同及有效,若不同则无效。
03.区块 ——以太坊
-
去开主要由区块头,交易列表,和叔区块三部分组成。
- 区块头:
- 父块的散列值(PrevHash)
- 叔区块的散列值(Uncles Hash)
- 状态树根散列值(stateRoot)
- 交易树根散列值(Transaction Root)
- 收据树根散列值(Receipt Root)
- 时间戳(Timestamp)
- 随机数(Nonce)
- 以太坊区块链上区块数据结构的一个重要改变就是保存了三棵Merkle树根
- 状态树
- 交易树
- 收据树
- 区块头:
-
存储三棵树可以方便账户做更多查询
扫描二维码关注公众号,回复: 3676117 查看本文章 -
交易列表是由矿工从交易池选择收入区块中的一系列交易
-
区块链上的第一个区块称为“创世区块”
-
区块链上除了创世区块意外每个区块都有他的父区块,这些区块连接起来组成一个区块链
-
以太坊大约每15s可以挖出一个新的区块
-
以太坊区块结构中状态树的更新
04.账户
- 账户以地址为索引,地址由公钥衍生而来,取公钥的最后20字节
- 两种类型的账户
- 外部账户
- 简称账户,他们都是由人创建,可以储存以太币
- 合约账户
- 合约账户是由外部账户创建的账户
- 以太坊中这两中账户统称为“状态对象”(存储状态)
- 外部账户储存以太币余额状态
- 合约庄户除了余额还有智能合约以及其变量的状态
通过交易的执行,这行状态对象发生变化,而Merkle树用户索引和状态对象的更新。
- 外部账户
一个以太坊的账户包含四个部分
- 该地址交易的次数,他是用于保障被一笔交易能且被处理一次的计数器,有效避免重放攻击
- 账户目前的以太币余额
- 账户的合约二进制代码(合约账户)
- 账户的储存(默认为空)
4.1 外部账户
- 外部账户(EOA)由私钥来控制,是由用户实际控制的账户
- 每个外部账户拥有一对公私钥,这对密钥用于签署交易,他的地址由公钥决定。
- 外部账户不能包含以太坊虚拟机(EVM)代码
我们可以做一个简单的对比,把外部账户看做用户在某个银行办理的一个账户,公钥就是用户为该账户设置的卡号,而私钥则是用户设置的密码。
一个外部账户具有以下特性:
-
拥有一定的账户余额
-
可以发送交易
-
通过私钥控制
-
以及没有相关的代码
-
用户在创建好战鼓后一定要记住私钥!如果用户忘记了,那你就滚吧。不可能不滚的。
-
秘钥通常保存在keystore目录下, 用户可以经常性的备份密钥文件,以防止忘记或者丢失
-
在以太坊节点之间传递整个目录后者密钥文件是安全的。但是账户的顺序可能会发生比改变。
-
用户需确保不要依赖或者更改脚本和代码段中的索引。用户自己列出自己创建的账户时,账户汇按字典排序,并且按照账户的创建时间先后排序
4.2 合约账户
- 合约账户是一个包含合约代码的账户
- 合约账户不是由私钥文件直接控制,而是由合约代码控制的
- 合约账户的地址是由合约创建时合约创建者的地址,以及该地址发出的交易共同计算得出
- 一个合约账户具有下列特性:
- 拥有一定的以太币余额
- 有相关联的代码
- 代码通过交易或者其他合约发送的调用来激活。
- 当合约被执行时候,智能操作合约庄户拥有的特定储存。
- 合约账户和普通账户最大的不同就是他还存有智能合约
- 以太坊区块链上的所有操作都是根据都是根据从账户发出的交易来执行的。
- 每当合约账户收到一条交易消息时,其他合约代码将被交易输入的参数调用执行。
- 而合约代码将会在参与到网络中的每一个节点上执行,并将执行结果作为新区块验证的一部分
4.3 私钥和公钥
- 公钥加密
-公钥认证
私钥的三种形态:
- Private key就是一份随机生成的256位二进制数字,该256位二进制数字就是私钥最初始的状态
- 而2以太坊钱包中,私钥和公钥将会以加密的方式保存一份JSON文件,存在keystore子目录下,这份JSON文件就是Keystore,所以用户需要同时备份Keystore和对应的Password
- 最后一种Memonic code是由BIP39方案,随机生成12-24个容易几乎记住的单词,随机种子,通过提案的方式生成确定性钱包
4.4 钱包
钱包就是一个比较形象的概念,一个外部账户通常由私钥文件来控制,拥有私钥的而用户就可以拥有对应地址的账户里的以太币使用权。
我们通常把管理这些数字密钥的软件成为钱包,而我们所所的备份钱包其实就是备份账户的私钥文件
-以太币钱包分类
-
Mist钱包
-
Parity钱包
-
Etherwall钱包
-
Brain钱包
-
钱包备份
- 防盗:分离备份
- 防丢:多处本分
- 分散风向:将资金适当的分散开
-
常见的钱包备份方式:
- 多处和分离备份
- 纸钱包
预防方案:用户可以痛死使用多重签名和多处分离备份,设定一个金额阈值,当用户提取超过该阈值的金额时需要多个私钥,另外把这些私钥多处分离备份,大大降低了资金被盗的风险
05.数据结构与储存
- 包括以太坊和比特币在内的大多是都是区块链项目,会使用Merkle树或者基于Merkle树的数据结构,比特币- 中保存了一颗Merkle树,而以太坊针对对象设计了三棵Merkle树,分别是状态树,交易树和收据叔,这三种树可以帮助以太坊客户端做一些简易的查询,查询某个账户的余额,某笔交易是否被包含在区块中。
- 区块,交易等数据最终都是存在LevelDB数据库中,LevelDB数据库是一个键值对数据库,key一般与散列相关,value则是存在储存内容的RLP编码
5.1 数据组织形式
- 以太坊使用Merkle Patricia树,(MPT),作为数据组织形式,用来组织管理用户的账户状态,交易信息等重要数据。
- MPT是一种加密认证的数据结构,他融合了Merkle树和Tire树(前缀树)两种数据类型的优点
- Merkle树
-
Merkle树是一种树行数据结构,可以是二叉树,也可以是多叉树
-
由一组叶节点,一组中间节点和一个根节点构成
-
最下面的叶节点包含基础数据,每个中间节点是他的子节点的散列,根节点是他的子节点的散列,代表了Merkle树的根部。
-
创建Merkle树的目的是语序区块的数据可以零散的传送
-
节点可以从一个节点下载区块头,从另外的源下载与其相关的树的其他部分,而依然能够确认所有的数据都是正确的。之所以如此是因为散列向上扩散,如果一个恶意用户尝试在树的下部加入一个伪造的交易,所引起的改动将导致树上的上层节点以及更上层节点的改动,最终导致根节点的改动以及区块散列的改动,这样协议就会将其记录为一个完全不同的区块(几乎可以坑定带着不确定的工作量证明)
-
如果底层的交易被篡改了,那么其对应的叶节点散列值也会改变,这件最终导致其Merkle树根值变化
-
Merkle树可以用来储存所有键值对
- 这颗树的建立从每个节点开始,将节点两两分成多达16个组,并对每个组求散列值,接着对散列结果继续求散列值,如此递归下去,知道整颗树有一个最后的根散列值。
-
Merkle树具有下列特性
- 每个数据集对应一个唯一合法的根散列值
- 很不容易更新,添加, 或者删除树节点,以及生成新的根散列值
- 不改变根散列值的话就没有办法修改树的任何部分,所以如果跟散列值被包括在签名的文档或者有效区块中,就可以保证这棵树的正确性
- 任何人都可以只提供一个到特定节点的分支,并且通过密码学方法证明拥有对应内容的节点确实在树里
-
- Merkle树
5.2 Trie树
- Trie树也叫做Radix树
- 在Radic树中,key代表的是从树根到对应value的一条真实的路径
- 即从根节点开始,key中的每个字符(从前到后)都代表着从根节点触发寻找相应value所要经过的子节点
- value储存在叶节点中,是每个路径的最终节点。
- 假如key中的每个字符都来自一个容量为N且包含的字母都互不相识的字母表,那么树中的每个节点最多会有N个孩子,树的最大深度便是Key的最大程度
- 优点如果有两个value,他们有着基于相同前缀的key,他们的相同前缀的长度占自身比例越大,则代表着两个value在树中的位置越靠近,并且Trie树中不会有像散列表一样的冲突,也就是说一个key只对应一个value,但是也存在着不平衡的
5.3 Merkle Patricia树
- 为了保证树的加密安全,每个节点通过他的散列值被引用,对于存储在LEVELDB数据库中的非叶节点,其中数据库中的表现形式:key代表着节点的RLP编码的SHA3散列值,value是节点的RLP编码。想要获得一个节点的内容,只需要根据该节点的散列值访问数据库以获得节点的RLP编码,然后解码即可。
- 在该方案中,根节点被称为整棵树的加密签名,如果一棵树给定Trie树的根散列值是公开的,那么所有人都可以提供一种证明,即通过提供每步向上的路径证明特定的key是否含有特定的值
- 引入很多节点类型来提供效率,MPT中节点包括以下4种:
- 空节点:简单的表示空,在代码中就是一个空串
- 叶节点:键值对的一个列表,其中key是一种特殊的十六进制编码,value是RLP编码
- 扩展节点:键值对的列表,但是这里的value是其他接待的散列值,通过这个散列值可以连接到其他节点
- 分支节点:一个节点为17的列表,MPT中的key被编码成一种特殊的十六进制的表示,再加上最后的value,前16个元素对应的key中的16个可能的十六进制字符,如果有一个键值对在这个分支节点终止,则最后一个元素代表一个值,即分支节点既然可以是搜索路径的终止,也可能是路径的中间节点
MPT还有一个重要的概念:用户对key进行编码的特殊十六进制前缀编码(HP),因为字母表中的字符都是十六进制表示的,所以每个节点最多只能由16个孩子,因为键值对有两个表示形式的节点,所以必须引用一中特殊的终止符表示,用来标示key所对应的值是真实的值还是其他节点的散列值。通过对终止符标识进行赋值,可以区分key所对应的节点的种类,无论key的长度是奇数还是偶数,HP都可以对其进行编码。
以太坊区块链系统中使用MPT树结构,但是每个以太坊区块头不是只包括一颗MPT树,而是为了三种对象设计了三棵树。
5.4 状态树
- 状态树中的每个节点16个孩子节点,每个叶节点表示一个账户,这些叶节点的父节点由叶节点的散列组成,而这些父节点再组成更高一层的父节点,直至到形成根节点。
- 状态树包含一个键值映射,其中键是账户地址,值是账户内容 {nonce,balance,codeahash,storageRoot}
- nonce是账户交易的序数
- balance是账户余额
- codeHash是代码的散列值
- storageRoot是另一棵树的根节点
- 状态树代表访问区块后的整个状态
- 账户的状态不是直接存储在每个区块中,所有的账户状态都是以状态数据的形式存在以太坊的节点中
- 状态数据是一种隐式的数据,意味着他需要从实际的区块链数据中计算出来,交易包含决定新状态数据的所有字段内容。与比特币不同的是,以太坊区块包含了整个状态树的Merkle树根散列和交易列表
- 状态树是用来记录各个账户的状态的树,他需要经常更新
5.5 交易树
- 每个区块都有一棵独立的交易树。
- 区块中交易的顺序主要由矿工决定,在这个块被挖出来前这些数据都是未知的。不过矿工一般会根据交易的GasPrice和Nonce对交易进行排序。
- 首先会将交易列表中的交易划分到各个发送账户,每个账户的交易根据这些交易的nonce来排序,每个账户的交易排序完成后,再通过比较每个账户的第一条交易,选择最高价格的交易,这写是通过一个堆来实现的、
- 每挖出一个新块,更新一次交易树
- 在交易树包含的键值对中,其中每个键是交易的编号,值是交易内容
5.6 收据树
- 每个区块都有自己的收据树,收据树不需要更新
- 收据树代表每个交易相应的收据
- 收据树也包含了一个键值映射,其中键是索引编号,用来指引这个收据相关的交易的位置,值是收据的内容
- 交易的收据是一个RLP编码的数据结构[medstate,Gas_used,logbloom,logs],其中 medstate是交易处理后树根的状态,Gas_used是交易处理后Gas的使用量,logs是表格元素的列表,表格有交易执行期间调用的操作码,address是生成日志的合约地址,topicn是最多4个32字节的值,data是任意字节大小的数据,logbllom是交易所有logs的布隆过滤器。
06.数据库支持-LevelDB
LevelDB是谷歌实现的一个非常高效的键值对数据库,其中键值都是二进制,目前能够支持十亿级别的数据量。在这个数据量下还有这非常高的性能。
以太坊中共有三个LeveleDB数据库:
- BlockDB: 保存了块的主体内容,包括块头和交易
- StateDB: 保存了账户的状态数据
- ExtrasDB:ExtrasDB保存了收据信息和其他辅助信息
LevelDB的用户接口,put(k,v),get(k,v) delete(k,v)
特性: - key和value都是任意长度的字节数组,一条记录(即一个键值对)默认是按照key的字典顺序存储,当然开发者也可以重载这个排序函数。
- 支持遍历,包括前向或者反向
- 支持原子写操作
- 支持过滤策略
- 支持数据自动压缩(snappy压缩算法)
- 底层提供了抽象接口,允许用户定制
限制:
- 不是sql类型数据库,没有关系模型
- 一个表只允许一个进程访问
- 单机系统没有服务器客户端
以太坊使用LevelDB主要考虑到他的写优化的特点