Hi 游客

更多精彩,请登录!

比特池塘 区块链前沿 正文
默克尔树
: E7 a& F) a5 }7 h; p6 ^! `! C( M3 d% [3 ?0 U( |
在讨论以太坊的主要数据对象之前,我想先向各位简要介绍一下默尔克树到底是什么,以使得它得以发挥作用的属性特征。
; l- p5 O7 g$ y( \8 ^5 B$ d, n$ ]4 |4 S
黄皮书中假设由定制的默克尔-帕特里夏树维护世界状态和交易。附录 D 描述了这个数据结构。3 M; {' e6 R$ |" p' {7 [1 X* h* T
- Q  i" v( N/ ?. g4 f
默克尔-帕特里夏树有许多有意思的属性,如果你想更深入地了解其在以太坊中的应用,我推荐你阅读这篇文章。
! n% E( X# B1 E; f
8 a# v3 f% G5 i8 K在默克尔树中,由叶子节点保存区块数据的哈希,而由非叶子节点保存其子节点的哈希。
# n! z) [) E7 k8 F  H& f- Q$ U( u* _+ n& F1 w
-默克尔树示意图(包括节点以及他们之间的关系)-
5 r* m) \% t# w' o% W/ M9 ~: v8 B7 ~% r( f$ f& P4 t
默克尔树所指向数据的任何改动都会引起节点哈希的变化。由于每一个父节点中所保存的哈希值都取决于子节点所包含的数据,所以子节点中数据的变更都会引起父节点哈希的变化。并且这样的影响是连锁反应,从叶子节点直达根节点的。因此对叶子节点所指向数据的改动会引起根节点所保存哈希的变化。由上述结构特征,我们可以引申出两条重要的属性:
: @1 R( D1 e5 Y! B, f" S- q- T3 I8 ]2 e' b
在判断两棵默克尔树所指向数据是否完全相同时,我们不需要比较每个叶子节点,而只需比较根节点所保存的哈希。
2 G+ w3 X% G# v1 p
( |* f: g# j, p1 l* d在判断特定数据是否被树所指向时,我们可以使用 默克尔证明 技术。此处不对该技术作过多介绍,只需知道这是证明数据存在于默克尔树中的一种简单、高效的方法。
/ \0 K4 S( e4 s
1 p0 A$ \3 }0 k( w0 o第一种属性的重要之处在于,我们能够仅利用根节点的哈希值,就标示某一时刻整棵树所指向的数据。这意味着仅通过保存根节点的哈希值就能标示区块(无需储存区块链中所有的数据),且维护数据的不可篡改。' x( k" Z) l+ s5 t! ], k* |
6 @8 t; O9 N4 s7 o  r
至此我们理清了默克尔树中根节点哈希的作用,下面来介绍以太坊中的主要对象。
4 T* {8 A& T- D1 u2 d% b# i2 Y* n0 X  W. C( G
世界状态
; k* O0 U+ W4 F- J9 u8 V" \0 K
" i4 f( o0 N8 N" Z世界状态是地址(账户)到账户状态的映射。虽然世界状态不保存在区块链上,但在黄皮书的描述中,世界状态也由树来保存数据(此树也被称为状态数据库或者状态树)。世界状态可以被视作为随着交易的执行而持续更新的全局状态。以太坊就像一个去中心化的计算机,世界状态则是这台电脑的硬盘。% ]4 F: ~$ V* Y  v$ r
1 D/ n; x( S. C* L6 r
以太坊中所有的账户信息都体现在世界状态之中,并由世界状态树保存。如果你想知道某一账户的余额,或者某智能合约当前的状态,就需要通过查询世界状态树来获取该账户的具体状态信息。下文中我也会简要介绍这些信息是如何存储的。( k+ L4 R- e8 L: E, g7 }' ]

. e4 K3 W! i9 y, e* i9 E$ ~# K7 J8 ?-世界状态树与账户存储-
2 w% q) H3 A5 i9 `* J" d, N/ f9 j
$ m  o( r1 Q% R-世界状态树与账户存储-
  @# h( O! O( E0 M; ^2 H- w8 O" G  G) x0 {. l
账户状态# l0 j3 l& d  s' @" f& j1 Z. u; y

' Y" d4 D5 |) U4 _) W以太坊中有两种账户类型:外部所有账户(Externally Owned Accounts 简称 EOA)以及合约账户。我们用来互相收发以太币、部署智能合约的账户就是 EOA 账户,而部署智能合约时自动生成的账户则是合约账户。每一个智能合约都有其独一无二的以太坊账户。- F; P0 c7 n, O& V
: g3 }: P+ e* [
账户状态反映了一个以太坊账户的各项信息。例如,它存储了当前账户以太币的余额信息、当前账户发送过的交易数量…每一个账户都有账户状态。# m6 [( a* ^) v4 w. F. E
5 {, Y) O) P6 I' |( ?- }0 X: D
下面就来看看账户状态中都包括什么:  S7 J- _" U; Z6 \9 A
+ t4 G8 T2 A* g. |) Y: c2 t  {
nonce
" t6 J0 w6 g2 k0 T/ D) F" Q7 Q; ]) ?0 c2 f1 j
从此地址发送出去的交易数量(如果当前为 EOA 账户)或者此账号产生的合约创建操作(现在先别管合约创建操作是什么)。* k7 h: o% ~- j/ Y8 P
- g8 h& y5 f+ G- `/ x5 B
balance
4 B4 R$ f' t9 \3 B& p
" s0 a0 A5 {& l- h4 G  |) M6 |此账号所拥有的以太币数量(以 Wei 计量)。
9 t3 u% \% H, }4 W; P4 ]" ?0 _) h$ e" Q4 B: [/ w' T5 x
storageRoot5 A: E5 i4 v& Q4 k4 ]+ l4 e
0 K: i" z6 g" h8 V. O
账户存储树的根节点哈希值(稍后介绍账户存储是什么)。
+ Q- A' H# k* x4 K- I
, p" }3 C. ]# k& z3 v6 r; BcodeHash! d/ d; n; y9 ]) {$ q- h

  S) M. `- b* y* g) v  P对于合约账户,就是此账户存储 EVM 代码的哈希值。对于 EOA 账户,此处留空。
% i$ Z5 i( {: C$ a: x4 l3 D  z
: K4 @: O) |# e: m& e4 C账户状态中不容忽视的一个细节是,上述对象在内的所有对象都可变(除了 codeHash)。举例来说,当一个账户向其他账户发送以太币时,除了 nonce 会增加,账户的余额也会相应改变。8 C8 K8 n: \3 S% F7 D# D" j# ]
( A' m8 R7 H+ I  [. r
而 codeHash 的不可变性使得,如果部署了有漏洞的智能合约,也无法修复更新此合约。对应的,只能部署一个新合约(而有漏洞的版本会一直存在于区块链上)。这也是为什么使用 Truffle 进行智能合约的开发和部署十分必要,并且用 Solidity 编程时要遵循 最佳实践 的要求。( Y2 p1 i& F0 c' {  `8 T2 \0 V: _

9 t# {% h& v% W: o2 V账户存储树是保存与账户相关联数据的结构。该项只有合约账户才有,而在 EOA 中, storageRoot 留空、 codeHash 则是一串空字符串的哈希值。所有智能合约的数据都以 32 字节映射的形式保存在账户存储树中。此处不再赘述账户状态树如何维持合约数据。如果读者对其内部实现感兴趣,强烈建议阅读这篇文章。账户状态中的 storageRoot 区域负责维持账户存储树根节点哈希值。
* t6 R( r2 |  @# o# y
- u+ \! f/ B& r5 i6 L( g$ x" \-账户状态与账户存储树-
. r* }1 t+ ^+ Z& M$ [4 N
2 f# Z& n. U2 z4 ?) h; H. P9 @7 G交易
$ ~4 U3 b& @* Q  b) v" R$ Q4 {/ Y7 x
+ f" t6 a- P/ R交易推动当前状态到下一状态的转变。在以太坊中有三种交易:. q7 Y5 H; R$ n; h, X$ p8 O9 I
6 a' ^% V+ G* R" L. ]" z- D
EOA 之间传输值的交易(例如,改变发送方和接收方余额大小)。
. w! z' i, O/ l( t% C+ [! j  \( d' c) N8 _6 h% o/ T
发送消息来调用合约的交易(例如,通过发送消息调用来触发 setter 方法,以设置合约中的值)。
/ f9 N  C- ^: r/ Y/ Q+ q3 i6 z. z" o' j
用于部署合约的交易(由此创建了合约账户)。3 Z; Q5 I0 a% G  ^

- J1 B# v' Z" \0 o( p/ ^0 q(从技术角度来讲,前两种交易是一样的…它们都是通过消息调用来改变账户状态的交易,只不过一个是 EOA 账户,一个是合约账户。此处将交易分为三种是为了方便读者的理解。)8 m$ f% K& z, P/ ]) M( x2 X
6 ~) m' E  `3 w9 h
交易由以下部分组成:. k$ G  c9 W3 I1 ]  y* \- _8 p

7 i1 Y) A! `( ?/ {! z/ `nonce) X; j/ R3 s  e

& f% w! {4 Q; u, _, ~: u2 m此账户发出的交易序号数(校对注:可以粗略理解为“这是该账户的第几笔交易”)。/ p9 f5 R9 P( g$ Q+ c" Z8 e9 \" v  _
- N! h( Q. K/ }
gasPrice
7 v( f% g3 J3 ]; A" k4 v! J6 H( T0 w* v" N: F2 w
执行此交易、进行计算时为每单位 gas 所支付的费用(以 Wei 计量)。6 ]0 J' g1 ?6 j, m
, Q! y4 w) d' O! h- K; _
gasLimit2 B5 \  t1 e, _: l7 t/ n" a
; J0 d/ s+ [. e  T" l8 E
执行此交易时可以使用的最大 gas 数量。
/ f2 k2 b$ h- O
* q+ K5 p; c! s# z4 Mto
" h- M2 e2 V% G  m8 d" {0 y; B. o. M$ M
如果此交易用于传送以太币,此处为接收以太币的 EOA 地址。% L) B7 D, w  y! l
% b4 l* u# r9 _: g1 D: K; T9 Q, o
如果此交易用于向合约发送消息(例如,调用智能合约中的方法),此处为合约的地址。3 i  T9 }" y6 |

! f5 |' n3 r# ^" i* M如果此交易用于创建合约,此处值为空。
3 Y- n0 M- S* M9 o. H
+ O  H2 R: J' T/ t- T7 Wvalue
0 h' ^  d% t* ^, s, u! a( w) e! f* y8 E0 N2 F
如果此交易用于收发以太币,此处为接收账户以 Wei 计量的代币数量。4 J( `2 X" K3 C) ~6 U% r

$ D5 b- R( r0 s: P2 G4 l' Y2 q- b如果此交易用于发送对合约的消息调用,此处为向接收此消息智能合约所给付的 Wei 数量。
! j# z) ]; b% K' \7 h
2 P6 r6 o/ P& Q如果此交易用于创建合约,此处为合约初始化时账户存放的以 Wei 计量的以太币数量。3 p) r2 i* g/ }* s) Z) t, {6 j9 C- U

: }+ C+ @* \+ \( Pv, r, s" W4 J$ f! z, t  e8 C8 N
% @% A" L4 A( M* g
在交易的密码学签名中用到的值,可以用于确定交易的发送方。
0 g: f- _- d4 r* w/ Q' W
( {# P+ R0 m3 N! {# x2 t- u) \data(只用于价值传输以及向智能合约发送消息调用)
5 K9 P) N3 ]: P+ L: c! s$ P( u7 ^1 \; }- s* m# E: D
发送消息调用时附带的输入数据(例如,假设你想要执行智能合约中的 setter 方法,数据区就应该包括 setter 方法的标识符,以及你想要设定的参数值)。5 l( b( X( ?) _# Y" }1 y

8 e+ R  v% V; ^; \- E3 oinit(只用于合约创建)
" E7 e; A/ K6 B0 k0 i/ `% ^( x7 n$ ?1 b, u$ F. {( {
用于初始化合约的 EVM 代码。. n5 V1 v& c1 c) u2 z1 l; [

& h" N0 j6 j8 F/ X* \) \别想着一下子就把这些概念消化完… 必须对以太坊的内部机理有更深的认识才真正理解、使用像 data 区、init 区这样的概念。2 _4 a/ |0 @- M

. N/ Q6 u) q% R3 c8 N6 }相信不出你的意料,区块中所有的交易也是存储在默克尔树中的。并且这棵树的根节点哈希值由区块头保存!下面我们就来剖析一下以太坊区块结构。
; K2 g# t( b5 J! ~" R: g
8 k0 z* Q3 o8 A! c' L0 a8 X$ [( ?区块0 N9 v; I+ ^6 X% S9 n7 |' n8 l

% e4 [0 _4 U9 r区块分为两部分,即区块头和区块体。) |0 m. U/ o9 Y2 k

# k& K% _6 @2 p! b+ y% E3 U) C) b$ A区块头就是以太坊中的区块链部分。它保存了前一个区块(也可称为父区块)的哈希值,通过区块头的连接形成了一条由密码学背书的链。" l( D/ }9 z( n! I. {% V  C

( b/ p* t) d. Y3 t  D8 x' w9 M区块体包含了此区块中记录的一系列交易,以及叔块(ommer)区块头列表。如果想要进一步了解叔块,我推荐阅读这篇文章。' ^  S' O2 _2 M" A; m* C- l( ]& @
8 E5 I/ f# A  p8 }" r
-以太坊区块的抽象示意图-
" Q# }3 c# V, Q& ]" O) F  G! d& k; ~" p+ @& R9 f: I
下面就来介绍区块头包括哪些部分。: P2 R, g' e" q, o5 B
- K) {9 a: p4 f& D; l1 a3 g
parentHash' \1 i& i2 Y% j$ G+ Q5 \

. W4 D* d, k4 u& i+ x  |前一个区块的区块头哈希值。每个区块都包含前序区块的哈希值,一路可回溯至链上的创世块。这也就是维护数据不会被篡改的结构设计(任何对前序区块的篡改都会影响后续所有区块的哈希值)。
! q3 V, Q% O' ~7 ?4 k" C" r8 c
+ i( q1 ]; p9 r/ j& j* v9 ^ommersHash3 B3 C' Q( J( q5 X6 |; L
3 ~5 N/ ?- P, R6 J3 ]
叔块头以及部分区块体的哈希值。
: k8 j4 Z, F0 I! q8 J# D; w+ c; u) O% \2 j( [1 t
beneficiary# z6 a, }6 h2 \6 t! K
. r* v1 R. Q5 A4 s0 |3 U/ ]1 P
因为挖到此区块而获得收益的以太坊账户。4 ]0 a3 {) _% P0 D' {3 n# S
6 o* b! ~9 F# d, D# ]
stateRoot0 k$ S! ^! K3 M* ^1 J" o! a' d

# V: B0 \: y/ S( t5 W世界状态树的根节点哈希值(在所有交易被执行后)。6 T7 s. \% d6 y  D: Y$ e. H1 G

! y5 R4 n9 e( {6 K2 m0 dtransactionsRoot# i! l' s6 T1 m% H2 [; c! P7 m, I
9 ~8 |5 G2 ?/ o! F
交易树根节点的哈希值。这棵树包含了区块体的所有交易。. {$ J& k8 C1 Q* ?; ?8 f
% X" I/ r! `+ u
receiptsRoot9 x7 {( b& N' [" T

4 Y. _# C& y4 ~; W6 f" f' m* T8 Q1 P每当交易执行时,以太坊都会生成对应结果的交易收据。此处就是这个交易收据树的根节点哈希。
0 O8 j! E# ]" \7 x. e! p/ Q! `( Z* G3 k
logsBloom
; E. i. n" d1 i1 R+ ]7 c6 P
& D6 k4 x# {4 R8 T- _布隆过滤器,用于判断某区块的交易是否产生了某日志(如果对这方面感兴趣,可以查阅 Stack Overflow 的这个答案)。这避免了在区块中存储日志信息(节省了大量空间)。
+ Q- h# i  U3 I! x8 p( K  h( M3 U. B2 }3 @3 [0 t
difficulty) G* t) [; r4 W$ s: d" U* O/ @

( r0 q6 C% ^5 V, Z' S此区块的难度值。这是当前区块挖矿难度的度量值(此处不对此概念的细节和计算作介绍)。
" R! Q% B1 O) m4 O& z: a$ C) a$ S* q/ i
number
* w# V1 z+ s& P$ j$ T  G: N) }) A# T) \4 U! j
前序区块的总数。这标示了区块链的高度(即区块链上有多少区块)。创世区块的 number 为 0 。5 a& J8 [2 h. o& o$ {

: s% L% X' D, Q" MgasLimit
' c: {! D2 o5 T' F  k( Z. `  ?( V' E! }1 t6 l/ G
每一个交易都需要消耗 gas 。gas limit 标示了该区块所记录的所有交易可以使用的 gas 总量。这是限制区块内交易数量的一种手段。1 f) n1 @5 r) y* a& `  t

8 U: b6 ^) U: D2 I# a4 lgasUsed2 Y2 U* W5 @' Q4 p0 a% \# v2 i" y" D: z

1 K* y; S" P# {' n/ J区块中各条交易所实际消耗的 gas 总量。
- x8 j+ `8 j5 b
0 H/ ?) K  J) a) H7 S4 ?% u& |timestamp- c4 W# R- a0 m9 Q) V, W

0 h$ @& t6 B( m; M区块创建时的 Unix 时间戳。谨记由于以太坊网络去中心化的特性,我们不能信任这个值,特别是撰写智能合约、涉及到时间相关的商业逻辑时不能依靠这个值。6 {' Y# W; m# S; Y
: j* ~+ p( ?3 S; f( |2 Y
extraData
+ u; q5 j0 L, ?; b" y
% U: I3 Q' l' h$ x/ c8 a* ]0 E能输入任何东西的不定长字节数组。当矿工创建区块时,可以在这个区域添加任何东西。* Y; b6 \- Y  t9 c
9 i$ ], b0 k1 s' O# E
mixHash' A8 Y' j$ m: Z( z
/ d$ x9 r- ]7 Q! v  A% Q
用于验证一个区块是否被真正记录到链上的哈希值(如果想要真正理解这个概念,建议阅读这篇文章 Ethash proof-of-work function )。3 t; `# ^( `2 ?2 v

, ?' r) o% j7 U3 \& D% M: Knonce
! V$ f6 v" b9 {) @% ]. h# r5 M6 c7 Z5 I: B0 x+ ^
和 mixHash 一样,用于验证区块是否被真正记录到链上的值。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

olwww 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1