Hi 游客

更多精彩,请登录!

比特池塘 区块链前沿 正文
默克尔树
2 B1 i4 @$ `/ b+ Y" w' i9 ~: m; T# e* F# L! C/ G% d" W
在讨论以太坊的主要数据对象之前,我想先向各位简要介绍一下默尔克树到底是什么,以使得它得以发挥作用的属性特征。
. W: W  _1 O) t# K# o2 Y5 Z; X$ K% n! s: g
黄皮书中假设由定制的默克尔-帕特里夏树维护世界状态和交易。附录 D 描述了这个数据结构。, p" P( a6 u; y2 j

9 m2 C% c$ c  m3 h9 j4 q/ Y默克尔-帕特里夏树有许多有意思的属性,如果你想更深入地了解其在以太坊中的应用,我推荐你阅读这篇文章。9 [+ G! G$ ~- t1 B5 \; f

4 f( Q6 L, s0 |4 _- W在默克尔树中,由叶子节点保存区块数据的哈希,而由非叶子节点保存其子节点的哈希。- h8 |# E" W: n, P
& q/ t7 ~+ d+ O
-默克尔树示意图(包括节点以及他们之间的关系)-
0 k- [4 z3 a1 r2 S$ a3 ?3 {5 ]8 s/ P; r) k7 \
默克尔树所指向数据的任何改动都会引起节点哈希的变化。由于每一个父节点中所保存的哈希值都取决于子节点所包含的数据,所以子节点中数据的变更都会引起父节点哈希的变化。并且这样的影响是连锁反应,从叶子节点直达根节点的。因此对叶子节点所指向数据的改动会引起根节点所保存哈希的变化。由上述结构特征,我们可以引申出两条重要的属性:, [) I3 M$ Q; L% ]7 d/ a

& S) X. _; f# ?6 X在判断两棵默克尔树所指向数据是否完全相同时,我们不需要比较每个叶子节点,而只需比较根节点所保存的哈希。, h& }) M1 t5 x: B! s% W

9 S' T& Y) e6 X5 G- S6 A" C在判断特定数据是否被树所指向时,我们可以使用 默克尔证明 技术。此处不对该技术作过多介绍,只需知道这是证明数据存在于默克尔树中的一种简单、高效的方法。4 i% Y; X6 e6 j; [

: A" R' f( M# U' V第一种属性的重要之处在于,我们能够仅利用根节点的哈希值,就标示某一时刻整棵树所指向的数据。这意味着仅通过保存根节点的哈希值就能标示区块(无需储存区块链中所有的数据),且维护数据的不可篡改。0 Q: Y- I8 d) y3 a

- R2 M( z$ i8 V( E4 X5 s至此我们理清了默克尔树中根节点哈希的作用,下面来介绍以太坊中的主要对象。
5 M0 E$ Q- X' X( T& g, \" D/ Y3 J; R
0 `& n( e5 \! p/ f世界状态7 }5 _9 E$ S# R. R% U: \
" |0 L8 B+ f- ^8 T$ \" L
世界状态是地址(账户)到账户状态的映射。虽然世界状态不保存在区块链上,但在黄皮书的描述中,世界状态也由树来保存数据(此树也被称为状态数据库或者状态树)。世界状态可以被视作为随着交易的执行而持续更新的全局状态。以太坊就像一个去中心化的计算机,世界状态则是这台电脑的硬盘。
% g  z0 @, _- [! v
" s0 \, g7 @$ N$ A$ z5 Y1 V以太坊中所有的账户信息都体现在世界状态之中,并由世界状态树保存。如果你想知道某一账户的余额,或者某智能合约当前的状态,就需要通过查询世界状态树来获取该账户的具体状态信息。下文中我也会简要介绍这些信息是如何存储的。
+ }/ O, b" y+ A# q/ h( ]# X* Q9 R
" l; b+ f+ I3 e1 E6 S6 x; L0 U# Z-世界状态树与账户存储-
6 T; B1 B+ \. i; b2 g$ O5 E/ f. h$ L, v$ g9 ^! V2 w: K, e
-世界状态树与账户存储-9 F3 ?4 X* T0 a  j- t% B4 Y

# s0 n% @% \* z账户状态
! C; G, ]" U$ H0 ]+ g5 L9 c' D; `1 e. S* Z% f0 m) x
以太坊中有两种账户类型:外部所有账户(Externally Owned Accounts 简称 EOA)以及合约账户。我们用来互相收发以太币、部署智能合约的账户就是 EOA 账户,而部署智能合约时自动生成的账户则是合约账户。每一个智能合约都有其独一无二的以太坊账户。
' e  x" n* g* x5 h+ N- E/ w$ m( N: j6 G
账户状态反映了一个以太坊账户的各项信息。例如,它存储了当前账户以太币的余额信息、当前账户发送过的交易数量…每一个账户都有账户状态。
: ?) s: p. M; C0 I$ S0 s; `) V! z& t2 p, T; x, n# b0 R
下面就来看看账户状态中都包括什么:! g7 c- |9 T, d( H2 K* L; o

6 a& k0 w- ?# D+ E. m, t+ lnonce- @( W9 o- N' `' I0 F, @$ I

5 U$ W: s& U1 P. H$ H1 ?4 S从此地址发送出去的交易数量(如果当前为 EOA 账户)或者此账号产生的合约创建操作(现在先别管合约创建操作是什么)。& R  n% F' a1 X8 P% }# \6 B
& G6 }# T: _" K7 n
balance
7 }+ ^/ m& F  L3 S* V/ \7 T: h
4 d' V) g3 Z* r( p2 A5 S" Y此账号所拥有的以太币数量(以 Wei 计量)。
0 ^. |) g- p* r; y2 e( X
) L% [: G+ e9 S0 c5 mstorageRoot
! |6 R* u1 E. z# I$ X; `& J5 M2 m: o; N
账户存储树的根节点哈希值(稍后介绍账户存储是什么)。
* }$ P2 n2 k$ d" Z8 I5 h0 W# Z9 c7 @( }9 ~. H
codeHash/ A2 ]8 U, e3 _+ ?: T& R4 C

5 d9 n9 x$ u" e; B( Y对于合约账户,就是此账户存储 EVM 代码的哈希值。对于 EOA 账户,此处留空。# }' K5 j0 A4 i( `
9 D$ f& n5 U  R# |; ~/ x6 m; ~5 ^
账户状态中不容忽视的一个细节是,上述对象在内的所有对象都可变(除了 codeHash)。举例来说,当一个账户向其他账户发送以太币时,除了 nonce 会增加,账户的余额也会相应改变。
  r5 M+ b/ d; Y0 R) x
- A: b: U! i1 J而 codeHash 的不可变性使得,如果部署了有漏洞的智能合约,也无法修复更新此合约。对应的,只能部署一个新合约(而有漏洞的版本会一直存在于区块链上)。这也是为什么使用 Truffle 进行智能合约的开发和部署十分必要,并且用 Solidity 编程时要遵循 最佳实践 的要求。% F: a1 B) q0 {6 j$ R
0 S- x- P; G1 A2 O" S
账户存储树是保存与账户相关联数据的结构。该项只有合约账户才有,而在 EOA 中, storageRoot 留空、 codeHash 则是一串空字符串的哈希值。所有智能合约的数据都以 32 字节映射的形式保存在账户存储树中。此处不再赘述账户状态树如何维持合约数据。如果读者对其内部实现感兴趣,强烈建议阅读这篇文章。账户状态中的 storageRoot 区域负责维持账户存储树根节点哈希值。" {: D& ]6 C$ ?: T
" W9 c( X& H* t4 F
-账户状态与账户存储树-
# Z# _' B; i9 l! `9 m  t
) H$ ^4 {8 p6 @, V交易2 k9 k% s6 c4 j

9 \7 `. e) x3 m6 r4 u# u6 z交易推动当前状态到下一状态的转变。在以太坊中有三种交易:' C' i2 E% X( |) p% \4 R( A: p
! p) K# M' a/ ^( r
EOA 之间传输值的交易(例如,改变发送方和接收方余额大小)。
: V" s& L# ?& X- ]  {# t" n
4 _7 R( K; R7 T+ F  S  M发送消息来调用合约的交易(例如,通过发送消息调用来触发 setter 方法,以设置合约中的值)。
0 k, M4 L1 D) a0 m! A
2 U; p& D2 _8 A9 A! D" T6 B用于部署合约的交易(由此创建了合约账户)。6 q" J0 h. P) |; M$ |

  R$ K. h5 v6 m1 O( ?# x. n- t. }( n(从技术角度来讲,前两种交易是一样的…它们都是通过消息调用来改变账户状态的交易,只不过一个是 EOA 账户,一个是合约账户。此处将交易分为三种是为了方便读者的理解。)
( x3 X" X- r& k2 u% J0 d# `' e! l
! E' f2 I- I0 ]8 [1 y交易由以下部分组成:
$ Q/ m; L- K' z. @) v& u/ A" @) {- t. t! J1 y
nonce6 m) W  b! s8 f- \* p+ S% q
4 F+ o' {7 o% X: t8 u# n; g
此账户发出的交易序号数(校对注:可以粗略理解为“这是该账户的第几笔交易”)。% J2 m0 B: y7 J! O- ]2 A
% y: T5 r8 d6 @" s/ X
gasPrice
3 Y8 l6 k  s4 r' j5 ]
% y' q7 X2 B% E! R$ ^/ a" `+ H+ K8 B执行此交易、进行计算时为每单位 gas 所支付的费用(以 Wei 计量)。
% ]- n" Y" E: @3 a1 C
4 l' Q( C! e. X& O/ l3 W1 p2 j) T$ w$ G% H. NgasLimit
) c6 G% ?* }9 p2 P; L" J7 p1 h4 c1 z) M5 G7 V
执行此交易时可以使用的最大 gas 数量。
' _1 D6 T; T8 F) g3 g) S3 @" Y; T8 C: C) w
to
9 Q# |7 |9 V9 C, E
; f! N& @; {8 H: u5 ^如果此交易用于传送以太币,此处为接收以太币的 EOA 地址。
1 }# p0 ~1 p& R+ ?1 ^3 v9 d7 O8 f2 B9 w& A# m
如果此交易用于向合约发送消息(例如,调用智能合约中的方法),此处为合约的地址。
7 l- s- d5 J9 Y% U
1 @/ N- E0 @3 t; c如果此交易用于创建合约,此处值为空。  _9 `3 {: a5 l! d
7 {8 u  w0 v" {+ {' P: q  c
value# M2 Q7 ?1 O3 D4 c
" z7 I- X9 ~6 r6 F' \! K; e
如果此交易用于收发以太币,此处为接收账户以 Wei 计量的代币数量。1 R+ r, Z7 s3 o. Q

6 m8 R9 N$ ]" v如果此交易用于发送对合约的消息调用,此处为向接收此消息智能合约所给付的 Wei 数量。0 E, K! s, n" K1 C5 i2 G

3 n3 K: T$ @% M如果此交易用于创建合约,此处为合约初始化时账户存放的以 Wei 计量的以太币数量。
# D* f! n: j- ~2 {5 ?
2 L" `1 n/ K& ]1 [8 Gv, r, s
8 q* Z0 f2 d6 j0 @! g# h3 E6 \
* O2 x& `' W  V4 p在交易的密码学签名中用到的值,可以用于确定交易的发送方。% H+ e, O  }# g
9 z4 g/ x9 G- y& T' u
data(只用于价值传输以及向智能合约发送消息调用), [4 E  Y+ U' S& X

. z: _- c7 |- g" Z( Y发送消息调用时附带的输入数据(例如,假设你想要执行智能合约中的 setter 方法,数据区就应该包括 setter 方法的标识符,以及你想要设定的参数值)。# `$ k% A4 ^" W" Z% A) m
* ?8 Z: `( M4 t* s
init(只用于合约创建)8 f7 C- @1 h; N5 g# w
3 b0 ~$ C* {4 _" v# t* f1 D
用于初始化合约的 EVM 代码。
' f3 K+ @2 u- y# }) p
, u3 g# s3 e# `8 T1 Z别想着一下子就把这些概念消化完… 必须对以太坊的内部机理有更深的认识才真正理解、使用像 data 区、init 区这样的概念。
8 k3 r0 o6 g* t- j  Y2 H3 S- Y$ T9 ?7 i
2 ^* F- J! u' q相信不出你的意料,区块中所有的交易也是存储在默克尔树中的。并且这棵树的根节点哈希值由区块头保存!下面我们就来剖析一下以太坊区块结构。1 y! W' [5 D- W& N; P5 o: K

% G$ j: B* q; m4 h1 W区块
' W3 r0 Y' {3 Y4 j! i: r& L" R! [) u9 n  z
区块分为两部分,即区块头和区块体。
6 [- S' K1 h( X$ m+ G" |2 T3 l2 Q5 y: N0 V) I0 J
区块头就是以太坊中的区块链部分。它保存了前一个区块(也可称为父区块)的哈希值,通过区块头的连接形成了一条由密码学背书的链。
( Q3 B; g- F1 f" P5 I6 C* {* e7 d* q* b8 r" Y9 k5 A# X
区块体包含了此区块中记录的一系列交易,以及叔块(ommer)区块头列表。如果想要进一步了解叔块,我推荐阅读这篇文章。0 v0 e  e% @4 ?5 R7 S, b7 b
) y/ Y9 S) c, W5 c; |
-以太坊区块的抽象示意图-
  S/ q# t* P1 o( O1 F" I
* O! B% @1 x: j& x2 j下面就来介绍区块头包括哪些部分。7 N' \9 d0 u& b7 I# J8 u/ r0 w
+ f6 y4 H4 _4 p7 j* _  Z2 Z
parentHash( x8 n1 ^" F) V, F

; u$ X7 \6 d1 m. ~, Y7 _前一个区块的区块头哈希值。每个区块都包含前序区块的哈希值,一路可回溯至链上的创世块。这也就是维护数据不会被篡改的结构设计(任何对前序区块的篡改都会影响后续所有区块的哈希值)。, \  Q; v' Y$ k! x) D, N) `( E

+ E, D. k+ T5 H5 ], x: y8 AommersHash% y& t( n+ Q2 g

' Y( W* F# S* T* S& h; I) F8 m! S叔块头以及部分区块体的哈希值。
4 ~9 _, f( b5 y5 k
, ~6 X- o: _) f, s/ ybeneficiary
8 c: n+ I" B) i0 G4 j
$ m* M# G- {' p( j5 |因为挖到此区块而获得收益的以太坊账户。2 b: y: L& T/ Y! h0 v

0 j8 q7 I: h* X0 N$ cstateRoot
2 d! v' D: X4 ?/ F3 H. Q
/ X7 M- i- n! D0 U# ]7 b世界状态树的根节点哈希值(在所有交易被执行后)。
" B- J5 u6 h% t  Z$ L' ]5 W# I9 W/ ]! H5 y0 \0 _
transactionsRoot* [2 H9 Q% S% G8 S
7 f9 h9 q# m; n  N% s* e* G& D; K! d
交易树根节点的哈希值。这棵树包含了区块体的所有交易。! t, `  n, y. I" H( X9 f6 l

! c  I) \9 A" y8 E' R  UreceiptsRoot
3 H% P, `( U4 T+ J8 s
; J6 L5 _# _1 l' z每当交易执行时,以太坊都会生成对应结果的交易收据。此处就是这个交易收据树的根节点哈希。
$ r/ K2 X* @( d+ v
5 b0 \( d( q! ~+ L) z' b' ClogsBloom
: f; z4 n8 E1 {& c6 `+ m
0 s5 K+ B( E4 D( ~4 n: m布隆过滤器,用于判断某区块的交易是否产生了某日志(如果对这方面感兴趣,可以查阅 Stack Overflow 的这个答案)。这避免了在区块中存储日志信息(节省了大量空间)。
. ~. y, P4 Z% Y2 o% v
+ z& x5 T% M* N5 a& w4 Ldifficulty
, A  w$ M' y% a# E) H$ r- V' d- H( H0 I; W
此区块的难度值。这是当前区块挖矿难度的度量值(此处不对此概念的细节和计算作介绍)。
0 d" m$ \. \7 r" t. J9 p  F8 U
2 T9 X+ }& |1 E) l9 e- e$ Vnumber8 U2 s7 m) p/ \2 i* m! ]

% `" z$ @0 h& I2 o前序区块的总数。这标示了区块链的高度(即区块链上有多少区块)。创世区块的 number 为 0 。. y; R" d) Z' D/ S  l
* v) R+ Q; {& D& T
gasLimit
/ G) B' T- P9 d
0 k3 k( v  @" D' G每一个交易都需要消耗 gas 。gas limit 标示了该区块所记录的所有交易可以使用的 gas 总量。这是限制区块内交易数量的一种手段。
' Q4 E- Z2 X8 L" O$ a2 a
& C4 `; }3 A# S$ b+ U! ygasUsed
" ?" O) X; h- F
$ i" O, o) M% E6 Y1 {+ d! G% `区块中各条交易所实际消耗的 gas 总量。) B- o5 ]3 V: |9 J; N% X  Q
, s$ K( m! L+ c6 u) Q
timestamp& q  j/ x) m) A+ B  p: ?1 a/ H" x

. h' D0 b* ?( f, x区块创建时的 Unix 时间戳。谨记由于以太坊网络去中心化的特性,我们不能信任这个值,特别是撰写智能合约、涉及到时间相关的商业逻辑时不能依靠这个值。: m% c' M! b2 }! J
" X7 f8 |$ A/ A' q6 F2 H
extraData
* H; G" T& E/ o8 I/ R, H9 w+ F7 T& i' O
能输入任何东西的不定长字节数组。当矿工创建区块时,可以在这个区域添加任何东西。
  @% r5 m' \' B6 x5 c5 r3 x3 w# v& A
mixHash1 r7 ]* F8 d2 Y) G: a

! W4 J6 Y- r9 x! A7 F% c用于验证一个区块是否被真正记录到链上的哈希值(如果想要真正理解这个概念,建议阅读这篇文章 Ethash proof-of-work function )。
, Y6 c& G+ w' \' Z/ p1 x7 l4 h: V+ A; }2 a+ }
nonce
3 l: n$ `" Z, Y) r( k& g2 j2 s
4 _3 C# C6 r3 ?- W1 B/ a: h: i: N和 mixHash 一样,用于验证区块是否被真正记录到链上的值。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

olwww 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1