Hi 游客

更多精彩,请登录!

比特池塘 区块链前沿 正文
默克尔树& p; x+ R" X, i2 s& t7 e
, M" ?0 M* ?. D% y! a7 B0 h7 l/ A
在讨论以太坊的主要数据对象之前,我想先向各位简要介绍一下默尔克树到底是什么,以使得它得以发挥作用的属性特征。$ E$ A4 k9 X, k4 }

' F, V: L% C5 w! R黄皮书中假设由定制的默克尔-帕特里夏树维护世界状态和交易。附录 D 描述了这个数据结构。
& K' G6 X: m! X% {, c7 B2 D! m, ^; h- Z
默克尔-帕特里夏树有许多有意思的属性,如果你想更深入地了解其在以太坊中的应用,我推荐你阅读这篇文章。
: p2 [) O3 J( a! X- _
5 i- O$ G3 m# e' k1 p* x在默克尔树中,由叶子节点保存区块数据的哈希,而由非叶子节点保存其子节点的哈希。; b6 c7 t( b7 y$ J5 i! m  S" e

$ l% e  w( N- k  W-默克尔树示意图(包括节点以及他们之间的关系)-
6 b7 X$ H2 `( N' `0 P; K' T! L& R% E! F0 _
默克尔树所指向数据的任何改动都会引起节点哈希的变化。由于每一个父节点中所保存的哈希值都取决于子节点所包含的数据,所以子节点中数据的变更都会引起父节点哈希的变化。并且这样的影响是连锁反应,从叶子节点直达根节点的。因此对叶子节点所指向数据的改动会引起根节点所保存哈希的变化。由上述结构特征,我们可以引申出两条重要的属性:& O% @" p, u' W2 x& A, ?/ ]

' r+ P3 l+ e& v6 |; B3 d在判断两棵默克尔树所指向数据是否完全相同时,我们不需要比较每个叶子节点,而只需比较根节点所保存的哈希。
* G8 Z: ^* s/ i! `
: B; X4 k5 ^; Z  H在判断特定数据是否被树所指向时,我们可以使用 默克尔证明 技术。此处不对该技术作过多介绍,只需知道这是证明数据存在于默克尔树中的一种简单、高效的方法。+ r. p6 m7 H* W/ C" X6 ]  l/ M8 ?
, a$ k1 i0 X+ D! C8 Q9 B6 C" {( t
第一种属性的重要之处在于,我们能够仅利用根节点的哈希值,就标示某一时刻整棵树所指向的数据。这意味着仅通过保存根节点的哈希值就能标示区块(无需储存区块链中所有的数据),且维护数据的不可篡改。2 Y3 C# Q3 E, O0 s' B

) A; A8 D" Y6 `* S至此我们理清了默克尔树中根节点哈希的作用,下面来介绍以太坊中的主要对象。( M0 g- J/ ]4 Z  q

5 G: b) [' O' o世界状态
. I6 X1 j. s4 Y3 J' c9 N' R; s6 q& T* X( n$ i7 K" C
世界状态是地址(账户)到账户状态的映射。虽然世界状态不保存在区块链上,但在黄皮书的描述中,世界状态也由树来保存数据(此树也被称为状态数据库或者状态树)。世界状态可以被视作为随着交易的执行而持续更新的全局状态。以太坊就像一个去中心化的计算机,世界状态则是这台电脑的硬盘。9 a/ \( o, a4 `# n

' ], ^0 G& }4 k( I3 [. ^2 g" \以太坊中所有的账户信息都体现在世界状态之中,并由世界状态树保存。如果你想知道某一账户的余额,或者某智能合约当前的状态,就需要通过查询世界状态树来获取该账户的具体状态信息。下文中我也会简要介绍这些信息是如何存储的。5 }, ^* G5 Q  [+ S2 o) ^3 w

8 [& ~. Q5 j3 Q- w5 ?8 `4 I-世界状态树与账户存储-
7 U% ^& |" ]9 x7 q6 J0 G5 _* B+ X8 d6 ?" a7 J
-世界状态树与账户存储-3 D3 l, C* m+ Q$ C& j/ j
: M. h  ]9 E" x6 K) e
账户状态
0 u8 |+ J. x2 n
# X: Z9 H4 c8 y+ S; B! u9 |以太坊中有两种账户类型:外部所有账户(Externally Owned Accounts 简称 EOA)以及合约账户。我们用来互相收发以太币、部署智能合约的账户就是 EOA 账户,而部署智能合约时自动生成的账户则是合约账户。每一个智能合约都有其独一无二的以太坊账户。# g& S- a) O9 b; g

& i) `, S% S( }账户状态反映了一个以太坊账户的各项信息。例如,它存储了当前账户以太币的余额信息、当前账户发送过的交易数量…每一个账户都有账户状态。
2 N9 o% W- Q; r/ z+ |/ k1 V, ^& G
, n8 l7 N7 _5 K+ F8 l; J9 L" M  f下面就来看看账户状态中都包括什么:+ [) r' Z% I6 S0 u7 c8 R

6 w; t- N7 p* x' t+ s7 mnonce- S, ^, |. i, w* a6 ]6 d( I3 ]

% f( K1 ?0 p0 J4 ~- ^+ f2 R* q从此地址发送出去的交易数量(如果当前为 EOA 账户)或者此账号产生的合约创建操作(现在先别管合约创建操作是什么)。' E! r$ q$ L% E4 a

- h. t: x& w% M3 ]8 vbalance9 j1 d) r4 m; {0 A: M. H, Q5 ~$ {
' m4 }$ u$ {+ \, J: u9 A
此账号所拥有的以太币数量(以 Wei 计量)。; M! I( U" |% N. J/ E
9 t8 I7 z+ Y; o% y: ]& k1 F9 q
storageRoot
0 b/ `3 V2 t1 p1 t
, x, T# @9 c% x& T账户存储树的根节点哈希值(稍后介绍账户存储是什么)。
, M8 q0 O5 j* n& A9 a
- N3 O" C9 N! G% C6 d* k6 pcodeHash" x  z! t+ r& V* ]5 J/ z5 V1 Z
# U: Z% r4 w) o- [; G9 g
对于合约账户,就是此账户存储 EVM 代码的哈希值。对于 EOA 账户,此处留空。* N. y" r1 j$ ~" S- x& T; R! A
: o2 C* r) E4 v0 p4 `
账户状态中不容忽视的一个细节是,上述对象在内的所有对象都可变(除了 codeHash)。举例来说,当一个账户向其他账户发送以太币时,除了 nonce 会增加,账户的余额也会相应改变。# Q/ q& K! V# K7 R& x
: k$ g% z* @- j* ?; c8 j* f
而 codeHash 的不可变性使得,如果部署了有漏洞的智能合约,也无法修复更新此合约。对应的,只能部署一个新合约(而有漏洞的版本会一直存在于区块链上)。这也是为什么使用 Truffle 进行智能合约的开发和部署十分必要,并且用 Solidity 编程时要遵循 最佳实践 的要求。
% s; `6 t: Y, y" X3 J) l" j1 q/ F& |4 O
账户存储树是保存与账户相关联数据的结构。该项只有合约账户才有,而在 EOA 中, storageRoot 留空、 codeHash 则是一串空字符串的哈希值。所有智能合约的数据都以 32 字节映射的形式保存在账户存储树中。此处不再赘述账户状态树如何维持合约数据。如果读者对其内部实现感兴趣,强烈建议阅读这篇文章。账户状态中的 storageRoot 区域负责维持账户存储树根节点哈希值。
3 l; a) E: e: Y. E
# c  T- J& N" l# s, r-账户状态与账户存储树-
! b- n! j- K1 Y7 B& d
$ F9 ^" Z# t3 B/ _5 z; i9 |3 A交易
: v; I" ~4 C2 @) q9 Y+ U; s1 [0 m( R, T& p) k- C5 o
交易推动当前状态到下一状态的转变。在以太坊中有三种交易:0 o! z8 a8 [9 C! u& `

  ^. K4 t' e6 q( K- gEOA 之间传输值的交易(例如,改变发送方和接收方余额大小)。# t$ Q) Z( }5 o- [: C5 }
9 j& N# Y0 l! N- f# Q/ `5 O. r3 K
发送消息来调用合约的交易(例如,通过发送消息调用来触发 setter 方法,以设置合约中的值)。! V" F1 u; E& W% x1 g. y* I
8 \* ^" F7 F+ ~- x
用于部署合约的交易(由此创建了合约账户)。- B5 m9 {& |2 U
  E; k1 n4 w& {+ f% D
(从技术角度来讲,前两种交易是一样的…它们都是通过消息调用来改变账户状态的交易,只不过一个是 EOA 账户,一个是合约账户。此处将交易分为三种是为了方便读者的理解。)# ^6 L5 k* _& i& H0 L

9 m, X$ X0 V# T9 I' E/ t交易由以下部分组成:
( }  L; n0 j9 c  D- {. K1 }0 O3 v2 b5 R0 R: b% Y# X) [, w' Z) {  r" D
nonce; r* N( N/ m" \; W  m' M! ?. ?3 k

+ ]* x# F- ?. H% O  H' j" t8 P此账户发出的交易序号数(校对注:可以粗略理解为“这是该账户的第几笔交易”)。, e% l% G8 b) f( M1 b
1 h0 x4 d4 s/ e7 V; `4 M$ m* z& R8 m
gasPrice
8 R, K$ r( D, h/ ^, b6 f; u: [% [0 L1 u
执行此交易、进行计算时为每单位 gas 所支付的费用(以 Wei 计量)。$ }  Y/ H, x3 o6 p4 b

5 ]. H! f1 K% d3 f* J, l* N- ugasLimit
* I! p7 x( G# U0 [8 q, f  v8 \* }' U' ~- K7 n1 f
执行此交易时可以使用的最大 gas 数量。
8 Y8 o; c0 V* u5 N! r
4 t& ?2 g* v3 ~4 Z( i6 a% ~; Ito  A8 I% v& x$ f1 ?# k! q
# q& t5 H( p1 F2 u
如果此交易用于传送以太币,此处为接收以太币的 EOA 地址。, N* Z5 d$ O' {2 P( w/ m

. k% P. G1 Z' _) t4 P7 H如果此交易用于向合约发送消息(例如,调用智能合约中的方法),此处为合约的地址。
* Z) Z, D! A7 T4 v6 v
- ~4 D+ y  A0 I( p% p* y5 U, v' Y8 u如果此交易用于创建合约,此处值为空。. F' T5 q: \$ B4 r* Y: X
' \1 w( A, S9 ~$ h
value; m# M8 M) R# Q

; _: b. J. Q) o- ?5 x) D4 K如果此交易用于收发以太币,此处为接收账户以 Wei 计量的代币数量。7 R& I' I% Z6 Z; ]9 W

1 D+ I) L" N# F! t# k( V如果此交易用于发送对合约的消息调用,此处为向接收此消息智能合约所给付的 Wei 数量。
% i1 V% n, v( L7 A
0 _7 c) z3 v3 e* D# H如果此交易用于创建合约,此处为合约初始化时账户存放的以 Wei 计量的以太币数量。$ }) y$ G2 E. R; f3 [& H
8 O% q- Y. i2 p* P& T& K
v, r, s
1 o6 j& t$ ~& `* S  l4 ~( s
( v% M: a$ D% Z( v$ b% _: ~在交易的密码学签名中用到的值,可以用于确定交易的发送方。
) v0 T) D& F3 r5 Z3 |3 \7 W. j$ |2 l. Q2 f
data(只用于价值传输以及向智能合约发送消息调用)/ y) O5 b, Q& }1 q) d9 ~) l: Y0 ?

# h7 ]' P& ]& ?4 r8 |发送消息调用时附带的输入数据(例如,假设你想要执行智能合约中的 setter 方法,数据区就应该包括 setter 方法的标识符,以及你想要设定的参数值)。
( n2 g/ R1 \8 u) i0 T& _4 l! D/ k* a
init(只用于合约创建)7 g8 w3 \( g2 Y; \0 }
. O9 t, E$ a% I4 o  t1 \. \
用于初始化合约的 EVM 代码。
+ k" ^3 R7 o, c4 J/ Y% h, R5 R( Y1 v: H" D: g, k+ W/ B6 Z) f+ U
别想着一下子就把这些概念消化完… 必须对以太坊的内部机理有更深的认识才真正理解、使用像 data 区、init 区这样的概念。
: u. ~/ g) T9 {* S( f
& `; @- Y: P1 S- ^& b# B, ^: K6 z相信不出你的意料,区块中所有的交易也是存储在默克尔树中的。并且这棵树的根节点哈希值由区块头保存!下面我们就来剖析一下以太坊区块结构。
* c& _1 i6 E& r+ Z" {3 E
* p% _, G; R2 G( Z1 ?" |区块
: B3 `4 V; p+ }: I7 f' p- d8 W5 b( {2 W. a3 w5 ^
区块分为两部分,即区块头和区块体。
* ~# y4 H' D, {5 d% ?) p! `# }* V4 Y, o4 N' N4 U
区块头就是以太坊中的区块链部分。它保存了前一个区块(也可称为父区块)的哈希值,通过区块头的连接形成了一条由密码学背书的链。
3 ^% B/ _+ ?0 @$ H4 ]) q( d. E% n5 d' l1 `: m6 o+ r2 j* @4 j1 G
区块体包含了此区块中记录的一系列交易,以及叔块(ommer)区块头列表。如果想要进一步了解叔块,我推荐阅读这篇文章。
5 J5 P8 f+ j" U+ I* l, l6 A& Q  R- }8 A  [7 Y; z0 I
-以太坊区块的抽象示意图-
5 B, G8 n* c' ^# `% m  \9 c3 }" t1 N" N) m# {
下面就来介绍区块头包括哪些部分。7 {, x7 a; S, w* t
  N- M! a6 V5 U6 b& K/ I- g
parentHash
# n  ]! `5 e& V6 a1 L
# k% L1 {9 Q2 \+ M前一个区块的区块头哈希值。每个区块都包含前序区块的哈希值,一路可回溯至链上的创世块。这也就是维护数据不会被篡改的结构设计(任何对前序区块的篡改都会影响后续所有区块的哈希值)。  X% u% @8 ~+ x, R  C5 W

; p% g' U- ?  d6 a5 M/ M& YommersHash
, A/ E- X% l4 _: _/ `. m% ~0 W, E6 p( [) [  B( a
叔块头以及部分区块体的哈希值。. i2 w! V! ^0 e: `
$ c) q; s! M6 F: L; B
beneficiary
. T3 e: Z7 Q" s4 x+ w( `" p4 R; p; [& Y- |0 f! H& ~
因为挖到此区块而获得收益的以太坊账户。
# C4 S8 U. C& e; J6 @. `3 L0 i  U1 ~
stateRoot
6 w( u, F  {9 n- |8 V! A" [
- \* U8 j" J% ]+ u世界状态树的根节点哈希值(在所有交易被执行后)。
! z7 Y5 e) l3 P- j
. a2 m/ d; R7 itransactionsRoot
, H2 j" l- b" l$ j% Q& a; K0 T, {. G( r
交易树根节点的哈希值。这棵树包含了区块体的所有交易。
0 j7 \6 m, z2 [0 p& |! K% M: D# S8 y% l; y  G9 `! y/ s# v
receiptsRoot  m" \6 t2 J1 t" b

4 T9 q+ j9 q- W- }每当交易执行时,以太坊都会生成对应结果的交易收据。此处就是这个交易收据树的根节点哈希。: V7 c; g( F! P

# s$ i7 `  S* e$ M% LlogsBloom/ e0 \  E+ c8 i& k, [  _( ~4 w6 }/ N& Q

( Z  \- D' R  {$ u1 I1 A7 v4 q7 x布隆过滤器,用于判断某区块的交易是否产生了某日志(如果对这方面感兴趣,可以查阅 Stack Overflow 的这个答案)。这避免了在区块中存储日志信息(节省了大量空间)。
* g4 z" W; R# k  N* |2 W: w+ V
3 o% |& h- ^# D( T# ^difficulty% L+ R& s, K+ k7 Z! q

7 J$ s% B" w/ ]- x& j此区块的难度值。这是当前区块挖矿难度的度量值(此处不对此概念的细节和计算作介绍)。* j% F9 F( \& O( [! I
% [7 v6 C3 U3 U3 {3 ^5 o  N. b
number
6 k5 ?5 T: d9 P' w
# t2 a% m/ r4 X1 K1 W, g- W3 Y前序区块的总数。这标示了区块链的高度(即区块链上有多少区块)。创世区块的 number 为 0 。% V0 S8 I5 D) @% \! F2 t8 h
- ]6 g# T4 m$ w# m4 k% s' s3 g" z# N
gasLimit
# i. r5 g# f. T& H7 d/ ^
% f* r! L, P. B5 [$ R. W8 B  n每一个交易都需要消耗 gas 。gas limit 标示了该区块所记录的所有交易可以使用的 gas 总量。这是限制区块内交易数量的一种手段。: r* J4 X8 i3 K. U, G& r2 a
6 b) t4 b) |: z4 A$ b6 R8 W6 @
gasUsed+ i- j) c5 B8 a! u" b* X" ^' [1 ~: u

+ a1 @7 w/ f* l, y区块中各条交易所实际消耗的 gas 总量。
; W; T* ^5 X; S! E3 ~$ ]
6 ~3 e$ m3 x& \. o; Itimestamp
- R, ^& X( n. N8 ?% A+ i8 l3 `' B  b/ _& q+ B' A
区块创建时的 Unix 时间戳。谨记由于以太坊网络去中心化的特性,我们不能信任这个值,特别是撰写智能合约、涉及到时间相关的商业逻辑时不能依靠这个值。$ X& |$ g# @% _( r5 R# @% ?8 W

7 j% x: G( B6 v* Z' u) g; cextraData+ n3 r" d  b5 s/ V( ~
/ Y& J+ F8 {# \" C
能输入任何东西的不定长字节数组。当矿工创建区块时,可以在这个区域添加任何东西。
9 L4 K1 @+ e/ ]6 d1 m
* |) S* S5 f7 g& e* Z' ?mixHash% N7 r9 R; B3 t
7 V$ [# d% P* h2 J+ g: d
用于验证一个区块是否被真正记录到链上的哈希值(如果想要真正理解这个概念,建议阅读这篇文章 Ethash proof-of-work function )。* J6 Z  B. G9 T$ D, `6 ~" f9 a

8 H5 P6 Y9 e9 }- a0 [: @: Tnonce. {: G( \8 ]- u8 A; J0 u* ?
9 c# M" U" T( j0 L* Y' |1 `
和 mixHash 一样,用于验证区块是否被真正记录到链上的值。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

olwww 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1