Hi 游客

更多精彩,请登录!

比特池塘 区块链前沿 正文
默克尔树, B  _$ S# `, I" H& E

0 p. R/ m9 F+ t6 u  T在讨论以太坊的主要数据对象之前,我想先向各位简要介绍一下默尔克树到底是什么,以使得它得以发挥作用的属性特征。
0 d( {& i: Z# i7 r3 @* f7 S3 z, V6 z) L/ J* Y$ s& g
黄皮书中假设由定制的默克尔-帕特里夏树维护世界状态和交易。附录 D 描述了这个数据结构。
3 g, H/ E& W: I4 t: }
/ w5 I5 h" b: Z1 E8 C( ^% ?' D默克尔-帕特里夏树有许多有意思的属性,如果你想更深入地了解其在以太坊中的应用,我推荐你阅读这篇文章。0 i! P1 ?- g) H& ?' c! B
3 Z& C6 F* p+ u3 l
在默克尔树中,由叶子节点保存区块数据的哈希,而由非叶子节点保存其子节点的哈希。1 \, h1 V$ A; ~5 Y1 L& Y6 h( n
( ?2 c5 p4 A4 g. n
-默克尔树示意图(包括节点以及他们之间的关系)-/ ~$ U8 c% q& @8 z; ^+ j1 k
, Z9 ]5 M9 Q5 x" s6 q  r, ?
默克尔树所指向数据的任何改动都会引起节点哈希的变化。由于每一个父节点中所保存的哈希值都取决于子节点所包含的数据,所以子节点中数据的变更都会引起父节点哈希的变化。并且这样的影响是连锁反应,从叶子节点直达根节点的。因此对叶子节点所指向数据的改动会引起根节点所保存哈希的变化。由上述结构特征,我们可以引申出两条重要的属性:: z1 M0 @  |+ J& p/ \% f

+ i8 f$ Q, y7 A& ~8 x3 l在判断两棵默克尔树所指向数据是否完全相同时,我们不需要比较每个叶子节点,而只需比较根节点所保存的哈希。
; g* o5 p8 m; m7 S; @: b9 P, Q+ ~" p
& l+ U# [- o# m- Z! M在判断特定数据是否被树所指向时,我们可以使用 默克尔证明 技术。此处不对该技术作过多介绍,只需知道这是证明数据存在于默克尔树中的一种简单、高效的方法。
* g7 M  M: C  Y& h$ E+ v2 [# ?: n" E7 K9 W  w  ^5 ~5 [9 t
第一种属性的重要之处在于,我们能够仅利用根节点的哈希值,就标示某一时刻整棵树所指向的数据。这意味着仅通过保存根节点的哈希值就能标示区块(无需储存区块链中所有的数据),且维护数据的不可篡改。
2 T; \: e' c0 F0 n0 s7 u! g4 X1 u" H; R( E
至此我们理清了默克尔树中根节点哈希的作用,下面来介绍以太坊中的主要对象。
; m( O7 C" _6 q& P- U' E+ V+ |2 ?
7 E( B7 G, a: w0 u. a% F世界状态
; d: a# y9 x2 G* `2 R( _+ x3 z
$ m$ G7 ^/ R2 ^6 @& Z/ a- Z6 X2 e世界状态是地址(账户)到账户状态的映射。虽然世界状态不保存在区块链上,但在黄皮书的描述中,世界状态也由树来保存数据(此树也被称为状态数据库或者状态树)。世界状态可以被视作为随着交易的执行而持续更新的全局状态。以太坊就像一个去中心化的计算机,世界状态则是这台电脑的硬盘。) n& {, F8 F% r2 f# \

7 o) Q1 I! R' Y0 r- p; f  D& _7 ?+ e以太坊中所有的账户信息都体现在世界状态之中,并由世界状态树保存。如果你想知道某一账户的余额,或者某智能合约当前的状态,就需要通过查询世界状态树来获取该账户的具体状态信息。下文中我也会简要介绍这些信息是如何存储的。
% K8 f* ?: Y$ F/ [3 m0 D' N; a' Q: O
-世界状态树与账户存储-# E: C# i2 a  D8 o( l/ J3 @
( ^4 {4 t& H% P0 c- j; V/ `
-世界状态树与账户存储-! r6 w5 k) `0 U6 [+ m, ]: c$ |5 O
8 D) N4 t* ~; b* Y# g; m0 J
账户状态+ x: g  r9 i( x  V" z

: O# L+ u" v8 H: g+ H! q- N  d以太坊中有两种账户类型:外部所有账户(Externally Owned Accounts 简称 EOA)以及合约账户。我们用来互相收发以太币、部署智能合约的账户就是 EOA 账户,而部署智能合约时自动生成的账户则是合约账户。每一个智能合约都有其独一无二的以太坊账户。7 d$ T6 z& X, ~/ s5 r
) ~5 k: ]. Q! O/ E, E
账户状态反映了一个以太坊账户的各项信息。例如,它存储了当前账户以太币的余额信息、当前账户发送过的交易数量…每一个账户都有账户状态。! i0 N' d, k, c

) b4 R+ |: v+ h! D- A9 K: a下面就来看看账户状态中都包括什么:6 Z. t3 Q5 x  p9 P4 ]

; H5 p3 V4 y0 `7 cnonce
3 r# U" K" x3 _; @) |% ?; ]! _7 n$ O
从此地址发送出去的交易数量(如果当前为 EOA 账户)或者此账号产生的合约创建操作(现在先别管合约创建操作是什么)。% t. `3 q; s( B% R% _

3 x! D7 p# c) V) E! m' Kbalance; Z3 R8 s& t' P2 w. K7 ?, L4 N
, l, m; e9 p9 S6 j2 {
此账号所拥有的以太币数量(以 Wei 计量)。0 _# }6 A8 \) C  m  R

2 F. ?5 i) ^6 g6 ]% k" istorageRoot
- U! ^& C8 ]& r( P' Q) x3 o5 s4 D7 I, {* O5 O
账户存储树的根节点哈希值(稍后介绍账户存储是什么)。9 P! X8 d% v# v: c' J& Y5 [
  Z+ X  v7 W" o6 r% @
codeHash
7 D0 X! }8 e6 _' f' m. I7 ]" w. ^
7 h+ y/ N  Q4 \: P对于合约账户,就是此账户存储 EVM 代码的哈希值。对于 EOA 账户,此处留空。3 f4 @" o  E5 X

; p0 C9 N9 h* r2 d1 ~账户状态中不容忽视的一个细节是,上述对象在内的所有对象都可变(除了 codeHash)。举例来说,当一个账户向其他账户发送以太币时,除了 nonce 会增加,账户的余额也会相应改变。+ ]4 t# h4 I& f6 G% ?/ g! M

$ u# |* @" n& W2 O& F+ i而 codeHash 的不可变性使得,如果部署了有漏洞的智能合约,也无法修复更新此合约。对应的,只能部署一个新合约(而有漏洞的版本会一直存在于区块链上)。这也是为什么使用 Truffle 进行智能合约的开发和部署十分必要,并且用 Solidity 编程时要遵循 最佳实践 的要求。; W; e" ]: J* R0 f2 d

' }: I3 U# B5 ^1 `% n( {; w1 z7 X账户存储树是保存与账户相关联数据的结构。该项只有合约账户才有,而在 EOA 中, storageRoot 留空、 codeHash 则是一串空字符串的哈希值。所有智能合约的数据都以 32 字节映射的形式保存在账户存储树中。此处不再赘述账户状态树如何维持合约数据。如果读者对其内部实现感兴趣,强烈建议阅读这篇文章。账户状态中的 storageRoot 区域负责维持账户存储树根节点哈希值。0 o" ^1 h2 i' [+ e: l
3 @  U' l" {' c2 m' p' R5 D& U
-账户状态与账户存储树-
% o% [, Q2 R" w# Y/ x% q) Z( }1 J+ ^' F5 }4 ]' ~( F. D- S
交易$ _$ x9 c. x( a" _$ o& }% W
( X. l( D  m/ {# x, r- R
交易推动当前状态到下一状态的转变。在以太坊中有三种交易:9 T# Z! m, l2 s2 D

6 q* Y, A0 {+ C6 Z2 S0 M; H3 IEOA 之间传输值的交易(例如,改变发送方和接收方余额大小)。+ v4 n" ?+ i1 v) [5 H" \) o
' X4 F+ o( ^& `) s$ V2 L
发送消息来调用合约的交易(例如,通过发送消息调用来触发 setter 方法,以设置合约中的值)。" N8 d: r. O0 r( K
3 s' T+ H/ W* I
用于部署合约的交易(由此创建了合约账户)。! l+ O6 Y, ]- B, L) m) |$ _

+ V$ L: t& ]+ V1 j* @(从技术角度来讲,前两种交易是一样的…它们都是通过消息调用来改变账户状态的交易,只不过一个是 EOA 账户,一个是合约账户。此处将交易分为三种是为了方便读者的理解。)
0 |) ?+ L0 j5 [8 D. w
4 k" d5 @( v5 @交易由以下部分组成:5 l7 d3 A! F+ n4 ?) c  ?2 k
, ^. I/ f# Y( b
nonce
3 d. e, E4 O( o7 s- j: ^
+ `+ h8 X7 Q8 G/ z! _- \此账户发出的交易序号数(校对注:可以粗略理解为“这是该账户的第几笔交易”)。
* [' o- E4 S' U& Z' j
+ X, w( ?, G/ d8 i* @2 PgasPrice
- y8 b5 m$ E. P( B3 @; s3 l; J. {- P* {
执行此交易、进行计算时为每单位 gas 所支付的费用(以 Wei 计量)。
( q- R9 o& T1 u! u- }# B- }6 Y6 z& y9 t1 C
gasLimit
/ v" y1 y" E/ j9 |- F! c3 O' N; Q& V" R1 q8 p' g# i3 z
执行此交易时可以使用的最大 gas 数量。
3 h, T0 F& `9 }! Y* _( b7 H
5 v; D; ~, O+ Z- x8 v5 Tto
! O8 r9 L5 U2 Z! t
3 I# i1 ~' _' o$ H% @& f( T如果此交易用于传送以太币,此处为接收以太币的 EOA 地址。
" a% H* {6 I" f" F  I/ F# j( h- y
如果此交易用于向合约发送消息(例如,调用智能合约中的方法),此处为合约的地址。
. l* X. ]4 L* K1 Y6 Q/ J* R: h$ c" g: I2 L
如果此交易用于创建合约,此处值为空。* a4 ~  N$ y* M7 T
4 u2 o- [! G6 x& M) P
value' ~- X; l) ^0 }4 {1 X, S

( z% F' o1 ~2 Q- }/ @9 f2 M4 }如果此交易用于收发以太币,此处为接收账户以 Wei 计量的代币数量。
' G! a! C: \8 G& ~: ^& u, {, @( f2 [! m. I$ s
如果此交易用于发送对合约的消息调用,此处为向接收此消息智能合约所给付的 Wei 数量。' {: m. O8 P' G/ Q
: r8 p) E% J: P' ]% _# f+ |
如果此交易用于创建合约,此处为合约初始化时账户存放的以 Wei 计量的以太币数量。
" z6 w7 ~2 m. D9 p8 S" m
1 N) D& n7 `% t, Wv, r, s- H5 N* h4 [; B+ x) `9 _
  z0 y' H3 @* J! N
在交易的密码学签名中用到的值,可以用于确定交易的发送方。( P6 E! K' B7 @; i

: Q: M- @  m$ ]' Q& ]: Jdata(只用于价值传输以及向智能合约发送消息调用)6 n: L. h$ @2 s  \) o% ~/ S: ~

" a2 I1 w( r7 S& b% }: L发送消息调用时附带的输入数据(例如,假设你想要执行智能合约中的 setter 方法,数据区就应该包括 setter 方法的标识符,以及你想要设定的参数值)。) s9 j8 X) G5 B/ V
# p; k: O: F, I, N8 ^
init(只用于合约创建)
4 `6 B" i% y5 u5 }) n% o# S% n+ A+ p4 o2 u
用于初始化合约的 EVM 代码。7 N/ h& o- @' a# {

  J5 z, H2 r3 X3 f1 n1 V1 Y$ e别想着一下子就把这些概念消化完… 必须对以太坊的内部机理有更深的认识才真正理解、使用像 data 区、init 区这样的概念。
6 n: H1 x; A  Q0 l  O  `5 l/ Q" w" z# k/ l
相信不出你的意料,区块中所有的交易也是存储在默克尔树中的。并且这棵树的根节点哈希值由区块头保存!下面我们就来剖析一下以太坊区块结构。% T2 P+ o' ?2 B9 _
7 V$ e) O( f: `$ x- L$ b# q
区块
) @6 q" j) t% q; \1 |4 g6 R7 s; r8 i
区块分为两部分,即区块头和区块体。' ?4 v. s3 O0 v) ]4 y9 E
; J* F/ ]0 E) q3 s; `8 [
区块头就是以太坊中的区块链部分。它保存了前一个区块(也可称为父区块)的哈希值,通过区块头的连接形成了一条由密码学背书的链。
2 E1 e; B2 u4 j3 ^6 X4 l$ n' y
( q% K( Q  U9 F2 E- U+ Q& s区块体包含了此区块中记录的一系列交易,以及叔块(ommer)区块头列表。如果想要进一步了解叔块,我推荐阅读这篇文章。/ {: T# \( K" F6 I7 o! y& B$ v. @

4 s  X: \! {( O1 e5 e- i* l, b. }-以太坊区块的抽象示意图-, `! }( ~1 `! q  ^# ?+ m! d

' n  D6 R! }4 }. n; Q下面就来介绍区块头包括哪些部分。
1 L2 m# L/ e* P" Z& [
0 m% Q- _* f7 ]  L- X9 k: p% u6 lparentHash& T- h7 J) Z' A. f
8 A+ N6 N9 s: v8 @' J: A
前一个区块的区块头哈希值。每个区块都包含前序区块的哈希值,一路可回溯至链上的创世块。这也就是维护数据不会被篡改的结构设计(任何对前序区块的篡改都会影响后续所有区块的哈希值)。  X8 f+ k; B. N, \- @

2 N- c" f: L& [8 _% {ommersHash
, F8 ~5 R# T" n. @* J; ~& ]9 C, c7 {0 V% z# _2 v' A7 c6 A
叔块头以及部分区块体的哈希值。
  @( c+ N" y! |4 H5 N- [. ]# u  |4 U
5 g& q2 A: G+ c% H: w% Xbeneficiary
7 D8 d$ y* E* F/ L1 Z/ X% _( ^* z, Q3 q+ b4 t
因为挖到此区块而获得收益的以太坊账户。
( n' A1 Y& p9 k" |0 S% x' o6 {  O4 S/ D
stateRoot% y! J, V! [& c. {5 j

7 i1 H$ a8 ?/ A0 u' T% c世界状态树的根节点哈希值(在所有交易被执行后)。  X+ i, O) R7 |' v9 z7 x

$ e9 l! S2 [3 d5 m' J+ Z9 s0 ?( btransactionsRoot% X8 s. a& n5 q' L
7 B( w* t  z* [% P7 [# V
交易树根节点的哈希值。这棵树包含了区块体的所有交易。: C0 v( W( ^7 b- t8 h( {  J/ t
' d1 O2 q! W3 e; C/ W% r. `% f
receiptsRoot
( {5 h) X% v( z) Y' B& G, i' ]3 {' L; S" |( ~
每当交易执行时,以太坊都会生成对应结果的交易收据。此处就是这个交易收据树的根节点哈希。& S3 @8 {. Q1 N; X
5 f. z' v6 y+ m& k9 D- |
logsBloom
7 ^! t/ X. Q! a: Y+ B
! X  f+ s5 U1 [布隆过滤器,用于判断某区块的交易是否产生了某日志(如果对这方面感兴趣,可以查阅 Stack Overflow 的这个答案)。这避免了在区块中存储日志信息(节省了大量空间)。( A+ d' T7 C: A( |7 I& \: L
5 R/ N, }, u, [% L- b% X$ h
difficulty- L, ]# h2 T2 b6 @7 \
6 f9 X; E% v" e$ w; r. D
此区块的难度值。这是当前区块挖矿难度的度量值(此处不对此概念的细节和计算作介绍)。& D, J/ l. }' [/ E
; {" x1 \4 d6 J+ X; [, e3 A5 ]
number- T  r4 V% C: Q* n: f5 n- R
6 u( D: _4 t( v5 H+ x4 _' P
前序区块的总数。这标示了区块链的高度(即区块链上有多少区块)。创世区块的 number 为 0 。" x, H" t$ O7 u$ q# N7 A, s' b

6 K  P$ b5 I" ^" a9 WgasLimit2 Z, \. {" D1 j0 J/ j) u2 N
1 P* |( D- y3 y) X
每一个交易都需要消耗 gas 。gas limit 标示了该区块所记录的所有交易可以使用的 gas 总量。这是限制区块内交易数量的一种手段。
9 H1 V5 A& H% j' |% r9 D! M8 z( A8 Z. z8 I( l! r
gasUsed0 `! b8 J4 F& c0 `, Z
( A7 U( C: v7 G( Q) C8 J. z
区块中各条交易所实际消耗的 gas 总量。
% m7 W- m1 E3 e& F6 I. `
% T: T3 ^' B) e* t9 i* ]+ o& stimestamp) M( f4 i5 |9 [: T3 _$ Y

7 {7 b. w7 R6 L区块创建时的 Unix 时间戳。谨记由于以太坊网络去中心化的特性,我们不能信任这个值,特别是撰写智能合约、涉及到时间相关的商业逻辑时不能依靠这个值。
9 s: X+ f  z/ G$ p5 q! i
3 M; j7 \" t6 k' U7 J& m# F( l4 uextraData% T- @1 F" e: @" P0 l. K

7 {5 g6 L; z5 h2 e; ]能输入任何东西的不定长字节数组。当矿工创建区块时,可以在这个区域添加任何东西。# w! j5 ?' p5 F( w- ~

( a3 K4 E$ c  U3 jmixHash1 b" A: V* D4 ]0 u  p4 o
3 k& O1 ^" F/ F  B, L4 Y& ~
用于验证一个区块是否被真正记录到链上的哈希值(如果想要真正理解这个概念,建议阅读这篇文章 Ethash proof-of-work function )。! l6 C- b! e; J( o

7 O4 j; Z/ b& {5 r7 xnonce
$ B9 t0 `4 S8 e2 E' c9 L# B1 f& t
1 n8 S7 B/ R" ^% h和 mixHash 一样,用于验证区块是否被真正记录到链上的值。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

olwww 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1