深入探索以太坊世界状态
茹蕙zx
发表于 2022-12-4 00:13:09
110
0
0
; w5 F6 [+ j% {7 ^
b)保存私钥
c)设置交易费用7 Q; ^5 T3 E: g( I" _; c
) }9 W7 j& P: ~- N( z6 H" f
d)提供找零地址6 r- X5 Z6 S7 ]* `1 D( T3 d
( m6 h: K+ K& c$ q
e)统计UTXO(显示可用余额、转帐中的数额以及总余额)有趣的是,一个非确定性钱包(如上图中的比特币核心钱包)的备份仅仅提供UTXO的快照(在该时间点)。只要用户执行了任何交易(发送或接收),他们所生成的原始备份就过期了。总结来说,我们知道: o6 [0 B3 h! D# }
$ K$ C5 l* K$ }5 v) N
比特币区块链不保存账户余额' l2 O1 M6 s1 H+ w
0 ]4 H5 `& w1 ~2 c$ z2 z- ~7 x
比特币
- Q* k" r& P$ ]/ e/ K& Q- U
[color=]钱包保存UTXO的私钥% v* f) G$ _4 T' S' g
当被包含在某一条交易中时,整个UTXO就被使用掉了(在有些找零场景中,原来UTXO中的价值会被新的UTXO承载)
和上述比特币网络不同,以太坊世界状态已经能管理账户余额以及更多信息了。以太坊中的状态并不是一种抽象的概念,它是以太坊的基础层协议。正如黄皮书[1]中所提及的,以太坊是一个基于交易的“状态”机。基于所有交易的状态机概念就这样被构建出来。让我们从头开始捋一捋,和其他区块链一样,以太坊区块链是由创世区块开始的。从这个起点开始(创世状态在0区块高度),诸如交易、合约以及挖矿的活动会持续不断地改变以太坊区块链的状态。在以太坊中,账户余额(存储在状态树中)随每一次交易进行所发生的改变就是这样一个例子。值得留意的是,像账户余额这样的数据并不直接保存在以太坊区块链的区块中。区块中只保存交易树、状态树和收据树的根节点哈希值。其存储结构如下图所示。从上图中可以注意到,存储树(所有智能合约数据存储的位置)的根节点哈希实际上指向了状态树,从而间接指向了区块链。接下来我们将深入探讨这一部分更细节的内容。以太坊中存在两种截然不同的数据类型:永久数据和暂存数据。交易就是永久数据的一个例子。一旦一个交易被确认,它就将永久地被记录在交易树结构中,并且无法篡改。而某一个特定以太坊账户的余额则是暂存数据的例子。账户地址的余额存储在状态树中,并且每当接收到和该账户有关的交易时,该余额都会改变。将挖矿确认后的交易这样的永久数据和账户余额这样的暂存数据分开管理是有意义的。以太坊使用前缀树这种数据结构(上图所示结构)来管理数据,那么接下来我们介绍一下什么是前缀树。前缀树前缀树是众所周知用于存储有序字符串的一种数据结构。以太坊特别采用了一种被称为“检索用文字数字编码的信息的实用算法”(Practicalalgorithmtoretrieveinformationcodedinalphanumeric,缩写为PATRICIA,下文音译“帕特里夏树”)树。帕特里夏树的主要优势在于它简缩的存储。接下来我们对比标准(传统)前缀树和帕特里夏前缀树之间工作原理的不同。–\0表示空指针-在前缀树中添加单词的规则我们跟随着所加入单词的搜索路径来看。如果我们(在搜索过程中)遇到了一个空指针,就构建一个新节点;当成功将单词加入到前缀树中后,我们再创建一个空指针(终止符)。当需要加入一个被其他长单词所包含的短单词时,我们就直接把所有的字母放进去并加入一个空指针(终止符)。从前缀树中删除单词的规则我们从前缀树中搜索一个表示字符串(我们所要删除的单词)的叶子(分支末端节点)。紧接着删除从叶子末端节点开始直到根节点的所有节点。除非我们遇到了一个有超过一个子节点的节点,否则删完为止。前缀树中搜索单词的规则我们依次检索所搜索字符串中的各个字母,直到得到一条完整的路径才停止搜索(在正确的顺序下)。如果在检索完字符串(检索目标)中的所有字母之前就遇到了空指针,那就可以说该字符串并不在该前缀树中。另一方面,如果我们随着检索到达了一个叶子节点(分支末端节点),那么该路径就代表着目标字符串,可以认为目标字符串在前缀树之中。帕特里夏树向帕特里夏树添加单词的规则帕特里夏树将所有的常用字符集合为一个分支。所有非常用字符都会成为路径上的一个新分支。当要向帕特里夏树添加一个新单词时,我们依次加入所有的字母,然后加入空指针(终止符)。从帕特里夏树中删除单词的规则从帕特里夏树中删除单词的规则整体上和传统前缀树一样,不同之处在于删除节点(从叶子节点到根节点)时,我们必须保证所有的父节点都至少有两个子节点。单个子节点只包含字符和一个空指针是允许的(如上图所示,每一个单词末尾都是这种情况)。同样允许一个节点只包含一个空指针(这种情况发生在短单词包含于长单词内)。上图中就体现了“wood”和“wooden”在同一个前缀树中的情形。值得留意的是,当要从一个前缀树种删除时,路径上不能保留任何只有一个子节点的父节点。如果在删除过程中发生了这种情况,我们需要把合适的字符重新连接起来以解决该问题。这种例子在下图中呈现(从前缀树种删除单词“word”)。-从前缀树中删除“word”之前--删除并重组前缀树之后-帕特里夏树中的单词搜索规则在Patricia前缀树中搜索单词和标准前缀树一致。标准前缀树和帕特里夏树之间的相似性假设“m”是我们要添加的字符串的长度,“N”是可用字母表的大小,将该字符串加入到前缀树的时间复杂度“O”为O(mN)假设“m”是我们要删除的字符串的长度,“N”是可用字母表的大小,在前缀树中删除该字符串的时间复杂度“O”为O(mN)假设“m”是我们要搜索的字符串的长度,在前缀树中搜索该字符串的时间复杂度“O”为O(m)标准前缀树和Patricia前缀树之间的主要区别使用帕特里夏树最大的优势在于存储方面。使用标准前缀树来存储总长度为“M”的字符串的空间复杂度为O(MN),其中“N”为可用字母表的大小。使用帕特里夏树来存储总长度为“M”的字符串的空间复杂度为O(nN+M),其中“n”是前缀树中存储字符串的数量,“N”为可用字母表的大小。直观来看能发现,两种树的深度显著不同(如上述两图所示)。帕特里夏树的深度更小(更浅),这归因于帕特里夏树将常用的字符组合的能力(并把空指针和叶子节点连接)更强。以太坊前缀树的深入探究让我们更深入地探究一下状态、存储以及交易前缀树。状态前缀树——独一无二以太坊中有且只有一个全局状态前缀树。这个全局状态树在不断地更新着。这个状态前缀树包含了以太坊网络中每一个账户的一组键值对。这个“键”是一个160位的标识符(以太坊账户的地址)。全局状态前缀树中的“值”是通过编码以太坊账户中的如下细节来得到的(使用递归长度前缀编码(RLP)的方法):1 F- v% Y9 J' {
nonce值
6 |& s, u+ o. D2 \0 s
余额2 h* o2 e7 Z# T3 X- }2 d# `6 m% d
! y7 W6 D( P0 H3 K X2 P
存储前缀树根节点哈希3 A( R: S( {# B! s. W0 v* q1 F
代码哈希
状态前缀树的根节点(在给定时间点整个状态树的哈希值)是用来确保状态前缀树安全的唯一标志符,状态前缀树的根节点是由整个内部状态树的全部数据来通过密码学手段得到的。-状态前缀树(用leveldb实现的默克尔帕特里夏树(缩写MPT))和一个以太坊区块之间的关系--给定区块中存储的“stateRoot”,这是用Keccak256位哈希算法计算状态前缀树根节点得到的。“stateRoot”:‘0x8c77785e3e9171715dd34117b047dffe44575c32ede59bde39fbf5dc074f2976’-存储前缀树——智能合约数据的存储存储前缀树是智能合约数据存储的位置。每一个以太坊账户都有自己的存储前缀树。在全局状态前缀树中保存着存储前缀树根节点的256位哈希storageRoot值(正如我们刚刚讨论的那样)。交易前缀树——一个区块一个树每一个以太坊区块都有着自己的独立的交易前缀树。一个区块往往包括多笔交易,而交易的顺序当然由打包交易的矿工来决定。在交易前缀树中找到一笔交易的路径是通过(RLP编码方法)检索交易在区块中的索引来得到的。已经被挖矿验证过的区块将永远不会再更新,所以区块中的交易顺序也将固定下来。这就意味着一旦你从区块的交易前缀树中定位到了某一笔交易,你日后就可以通过相同的路径找回它。
成为第一个吐槽的人