Hi 游客

更多精彩,请登录!

比特池塘 区块链前沿 正文
默克尔树
7 H% {3 x" O) z! d; p& @4 U% A0 g) C
在讨论以太坊的主要数据对象之前,我想先向各位简要介绍一下默尔克树到底是什么,以使得它得以发挥作用的属性特征。
# z- Y! B4 L& ~, B+ ~# A8 g1 {2 N$ N) ]% j
黄皮书中假设由定制的默克尔-帕特里夏树维护世界状态和交易。附录 D 描述了这个数据结构。
* S& C; M. O9 q
; K" c* f- B. P( B7 X默克尔-帕特里夏树有许多有意思的属性,如果你想更深入地了解其在以太坊中的应用,我推荐你阅读这篇文章。
! j+ I1 F6 u. V' d& r) k( j
0 k+ f2 U9 P  Z4 F" U* A9 t! r在默克尔树中,由叶子节点保存区块数据的哈希,而由非叶子节点保存其子节点的哈希。
$ m% g! D, @3 Y" J
* O5 d1 j3 b8 l' v-默克尔树示意图(包括节点以及他们之间的关系)-. |3 m+ Z: L2 e6 n3 y5 M% W, g4 Y" L# s& I
- V* ?6 v4 x' l$ q/ ^- V) r3 }
默克尔树所指向数据的任何改动都会引起节点哈希的变化。由于每一个父节点中所保存的哈希值都取决于子节点所包含的数据,所以子节点中数据的变更都会引起父节点哈希的变化。并且这样的影响是连锁反应,从叶子节点直达根节点的。因此对叶子节点所指向数据的改动会引起根节点所保存哈希的变化。由上述结构特征,我们可以引申出两条重要的属性:
* F& U+ _; Y# x1 A; G% P
; f$ L7 L9 s. g; ^# R  c2 `在判断两棵默克尔树所指向数据是否完全相同时,我们不需要比较每个叶子节点,而只需比较根节点所保存的哈希。
3 K; m7 x$ P6 z: Y
; Q7 x! c, m, G* ?0 ]在判断特定数据是否被树所指向时,我们可以使用 默克尔证明 技术。此处不对该技术作过多介绍,只需知道这是证明数据存在于默克尔树中的一种简单、高效的方法。+ E7 U) Y& s, v; y0 N, A* Y8 u2 F

. n. R9 {# O7 A% _* p: U第一种属性的重要之处在于,我们能够仅利用根节点的哈希值,就标示某一时刻整棵树所指向的数据。这意味着仅通过保存根节点的哈希值就能标示区块(无需储存区块链中所有的数据),且维护数据的不可篡改。
2 r6 M' v# o, @# I: l) ]! v% b% C- n8 D0 s9 l
至此我们理清了默克尔树中根节点哈希的作用,下面来介绍以太坊中的主要对象。+ m- S* h' Y) d. t: A$ O
* w8 @$ s9 _. ?# {
世界状态7 p" j0 d' ]* M- ~
! |) E9 ?" o3 m' z
世界状态是地址(账户)到账户状态的映射。虽然世界状态不保存在区块链上,但在黄皮书的描述中,世界状态也由树来保存数据(此树也被称为状态数据库或者状态树)。世界状态可以被视作为随着交易的执行而持续更新的全局状态。以太坊就像一个去中心化的计算机,世界状态则是这台电脑的硬盘。
0 W! r* l, @/ H1 [2 [0 M
9 F$ F4 y) k9 c- W6 l. S! v以太坊中所有的账户信息都体现在世界状态之中,并由世界状态树保存。如果你想知道某一账户的余额,或者某智能合约当前的状态,就需要通过查询世界状态树来获取该账户的具体状态信息。下文中我也会简要介绍这些信息是如何存储的。
8 I" {# C2 H* ^3 O; v, v; t0 m" Z1 P' m8 x
-世界状态树与账户存储-
; s+ y% E7 e1 Z! i# G4 P* T. t0 ^) ]: {8 ^; ^$ k6 |$ ]2 @
-世界状态树与账户存储-) u+ ?. u! u- s6 ], p

- \9 g2 ?5 a6 v* W' A; o* u账户状态6 k% H. B6 S  Q2 s
# z  {- G7 d4 I3 }1 Q
以太坊中有两种账户类型:外部所有账户(Externally Owned Accounts 简称 EOA)以及合约账户。我们用来互相收发以太币、部署智能合约的账户就是 EOA 账户,而部署智能合约时自动生成的账户则是合约账户。每一个智能合约都有其独一无二的以太坊账户。4 q) Z& f3 Z7 t, o. p- n$ Q
6 O. x! j2 Y0 e  h( J7 p
账户状态反映了一个以太坊账户的各项信息。例如,它存储了当前账户以太币的余额信息、当前账户发送过的交易数量…每一个账户都有账户状态。' S1 x5 b0 T# c3 k6 u4 }6 E1 L) J

/ W" e# u2 B, I- Y9 f0 M下面就来看看账户状态中都包括什么:  n* t& e" J7 p: m' ]; `) Q" |1 c

) U! B  p% `2 Q' L- t1 i$ vnonce
  U. E" W8 O4 O! O3 ?) K9 {% _  d3 d4 }; o4 F4 u
从此地址发送出去的交易数量(如果当前为 EOA 账户)或者此账号产生的合约创建操作(现在先别管合约创建操作是什么)。
8 d' ^4 ~: I% k* n% o6 k4 o, U- J9 n; _. s
balance
* v- S# o, X  E5 G' I7 ?1 g: W) n. `! t* c% K: e# Z
此账号所拥有的以太币数量(以 Wei 计量)。& W2 Y8 {/ ^# E3 m+ [( C0 y
: }' Y$ s+ [( O$ A4 D
storageRoot4 x  i1 L! y2 N6 f/ u
* j" L& `  n3 z8 \" w6 N
账户存储树的根节点哈希值(稍后介绍账户存储是什么)。
" |: C8 v% ?9 m" Z  B/ T3 m6 [, Q0 T' H, u, p6 B9 T/ V/ P
codeHash  z/ B+ x% n+ ]/ W% \5 B/ [0 p
6 M7 D# a% Q  M" J7 G. h
对于合约账户,就是此账户存储 EVM 代码的哈希值。对于 EOA 账户,此处留空。! f/ e7 b; M$ I( J: d1 g) j& U5 P

1 n! X4 _2 y0 T账户状态中不容忽视的一个细节是,上述对象在内的所有对象都可变(除了 codeHash)。举例来说,当一个账户向其他账户发送以太币时,除了 nonce 会增加,账户的余额也会相应改变。5 `7 H" L5 G' c9 A' l
# `: e) S1 y8 Z) w  q. k$ l
而 codeHash 的不可变性使得,如果部署了有漏洞的智能合约,也无法修复更新此合约。对应的,只能部署一个新合约(而有漏洞的版本会一直存在于区块链上)。这也是为什么使用 Truffle 进行智能合约的开发和部署十分必要,并且用 Solidity 编程时要遵循 最佳实践 的要求。
8 I$ \7 ^  N: t& o# D
3 p6 c+ _: R/ w6 T/ c& n账户存储树是保存与账户相关联数据的结构。该项只有合约账户才有,而在 EOA 中, storageRoot 留空、 codeHash 则是一串空字符串的哈希值。所有智能合约的数据都以 32 字节映射的形式保存在账户存储树中。此处不再赘述账户状态树如何维持合约数据。如果读者对其内部实现感兴趣,强烈建议阅读这篇文章。账户状态中的 storageRoot 区域负责维持账户存储树根节点哈希值。% W9 R; Y5 `2 F2 a' J1 X

$ i$ J+ O7 o' e- T-账户状态与账户存储树-
- |, |% n; F* }* Q, I, L2 i% W' Z7 C
' E, o" f2 J! l7 S1 b0 c7 {9 `, {! w6 W交易
8 l# f; u0 o3 k6 y
9 [4 R6 b. F1 X& E$ T$ f' E0 e* [交易推动当前状态到下一状态的转变。在以太坊中有三种交易:. |. b9 D) @+ e9 C3 o6 _
+ A! g/ R5 U+ D- l  }6 [
EOA 之间传输值的交易(例如,改变发送方和接收方余额大小)。
7 ?+ b+ J6 c& F0 Z( D& q2 L# _5 Z3 K
发送消息来调用合约的交易(例如,通过发送消息调用来触发 setter 方法,以设置合约中的值)。- e0 E/ S( F" \

) M% L% l; }) K% A; v- F0 }; e- {用于部署合约的交易(由此创建了合约账户)。+ k) c" M% R6 b: o8 s

  x( Z. ]# \# X, d# P4 o& p(从技术角度来讲,前两种交易是一样的…它们都是通过消息调用来改变账户状态的交易,只不过一个是 EOA 账户,一个是合约账户。此处将交易分为三种是为了方便读者的理解。)3 x& M% }5 ^$ l  S# [
/ X! M- x3 Q1 ~; f
交易由以下部分组成:
& K& \! z- `: v' V4 t# R' w  l
nonce, F; t+ Q) u6 Z$ _
4 [- x0 n5 f# A  p
此账户发出的交易序号数(校对注:可以粗略理解为“这是该账户的第几笔交易”)。  B$ k& A, @8 \6 z! ?
: H, [, E7 m# b' d
gasPrice
. G& h3 [* C) Q1 `
" i/ Z" o8 y4 i' N, L8 K4 z执行此交易、进行计算时为每单位 gas 所支付的费用(以 Wei 计量)。
  E, k4 f7 V) e) P
! P: B) H9 {) @9 F  D" V0 {gasLimit
! f7 O/ l2 o0 O
* O! ^9 M  I! J2 t1 M% l: u执行此交易时可以使用的最大 gas 数量。
1 m/ q& z1 }# u* M" u% h2 A5 s
' A6 _$ S5 H% D, h& |. d8 Cto" A+ p1 U$ P4 r* V( [- m
: W3 Y5 f; v- w+ T% d- S9 L' g$ T5 Y
如果此交易用于传送以太币,此处为接收以太币的 EOA 地址。
/ Z+ U! ^& X) u4 n! o/ P, U; F
" t% D$ `) P2 p4 P6 [9 B如果此交易用于向合约发送消息(例如,调用智能合约中的方法),此处为合约的地址。8 P( T" ?  j* \2 W3 d" x
) w6 S: l( Q, ~5 P, y* {
如果此交易用于创建合约,此处值为空。
8 U! k3 @% I; ~0 G) Q: O' \4 F+ y9 w+ N. ^) h# B+ m/ l
value3 `. j  @; W/ w8 j/ ^' d% |- L3 x
! H! Y, E- Q) V1 R% w
如果此交易用于收发以太币,此处为接收账户以 Wei 计量的代币数量。! O0 D2 Q# D! c! ?
& F$ O) C5 s: E
如果此交易用于发送对合约的消息调用,此处为向接收此消息智能合约所给付的 Wei 数量。
* ?  M  F/ N, R# F3 y/ E  ]5 n1 _/ t
如果此交易用于创建合约,此处为合约初始化时账户存放的以 Wei 计量的以太币数量。
8 B2 y0 q5 ?& ?# }/ j" o1 s. P; T8 w; o' ~- Z8 M
v, r, s. }  B) y4 z9 M

* \( O- ?8 P+ a* M' Q7 F在交易的密码学签名中用到的值,可以用于确定交易的发送方。
" @/ E; x, r4 y/ {( a7 S7 n
. k! T; R8 [8 |- Ddata(只用于价值传输以及向智能合约发送消息调用)% p8 B/ K7 s* k9 [

& e0 P4 t3 z, q" {发送消息调用时附带的输入数据(例如,假设你想要执行智能合约中的 setter 方法,数据区就应该包括 setter 方法的标识符,以及你想要设定的参数值)。7 r7 Z% R0 k2 k6 [5 Z+ `6 c0 w6 |" A
* n  i4 k- p0 M1 B' ]( ]
init(只用于合约创建)
7 {4 E; c* w% U
, [1 Z: w# ^9 t6 x% V" M5 r用于初始化合约的 EVM 代码。  |' [9 B4 G2 c" R8 i

2 ~% a5 T( i! I别想着一下子就把这些概念消化完… 必须对以太坊的内部机理有更深的认识才真正理解、使用像 data 区、init 区这样的概念。
8 F, }8 f# O$ L1 }, D1 G$ y
! b* E! P' f$ [' ]) x相信不出你的意料,区块中所有的交易也是存储在默克尔树中的。并且这棵树的根节点哈希值由区块头保存!下面我们就来剖析一下以太坊区块结构。
7 Q5 L8 `5 O- Q4 a7 P- c+ x. g% I1 t3 a& t3 Q- X
区块) s" w+ N2 O6 Z( u
% v, y$ O2 Q  i0 w
区块分为两部分,即区块头和区块体。1 \: Q' @0 o7 H1 o% @
( |; O: U" [' s
区块头就是以太坊中的区块链部分。它保存了前一个区块(也可称为父区块)的哈希值,通过区块头的连接形成了一条由密码学背书的链。! S; |$ }. ]+ n, s+ I1 w, j

& t! v* r9 J. N8 f6 H区块体包含了此区块中记录的一系列交易,以及叔块(ommer)区块头列表。如果想要进一步了解叔块,我推荐阅读这篇文章。' K$ J0 t6 W6 d! {
, }0 |  u! Z  \5 H; b- ^( k
-以太坊区块的抽象示意图-% X' w0 ~2 z2 X0 p1 z
' f& f; t! @1 A0 k: T( O
下面就来介绍区块头包括哪些部分。4 j1 z( R7 Y2 T% f" M. U
1 }1 s6 S; V0 q% D6 p
parentHash
5 P1 {- ~5 N$ g/ {& P1 C$ i1 N+ b4 H- k% Y' |; U
前一个区块的区块头哈希值。每个区块都包含前序区块的哈希值,一路可回溯至链上的创世块。这也就是维护数据不会被篡改的结构设计(任何对前序区块的篡改都会影响后续所有区块的哈希值)。+ T- [5 j7 L% A
  s+ C2 ~$ k5 c2 v7 J, ?
ommersHash
5 A' J" x4 m5 Z: x! q) X1 i* g2 @9 u7 C
叔块头以及部分区块体的哈希值。! U+ q5 ~4 {- R5 r5 p

( J8 D) z* ?5 W# L) }7 ubeneficiary
2 d- p& [) S& g8 u5 z" E! w! O* e2 f4 a* ?) K8 A% l
因为挖到此区块而获得收益的以太坊账户。
# Z! P. t, Q1 r+ L& x7 a, J4 q% X/ E/ I7 N, k* |
stateRoot
  t" n$ |& j( R* j& c/ f
" b, y! t1 V. j5 a0 G: h世界状态树的根节点哈希值(在所有交易被执行后)。
+ F5 D/ [, y4 w2 `) T
. G8 [, \/ ~# g; FtransactionsRoot4 ^- T6 e' Z8 S+ W4 ^8 Z

" l/ V! @% Y! R1 D4 L交易树根节点的哈希值。这棵树包含了区块体的所有交易。4 w$ h  V- ?  S3 M1 S& N
+ N. i7 H7 l: ~) ^: O% N
receiptsRoot
9 R5 ~, ~- Q' {, ?7 \
0 R6 x- i. `' O3 i' ~: E, _每当交易执行时,以太坊都会生成对应结果的交易收据。此处就是这个交易收据树的根节点哈希。
& m! T- f$ W5 u, |7 J
% x* ?: F  ]4 o" G( flogsBloom
. `+ M3 P+ _& O5 N3 j, p, r  ^0 i3 x( ~
布隆过滤器,用于判断某区块的交易是否产生了某日志(如果对这方面感兴趣,可以查阅 Stack Overflow 的这个答案)。这避免了在区块中存储日志信息(节省了大量空间)。( A6 H! R- @; `: d' }

% i- f2 ~$ f3 x  S- E& Gdifficulty+ l! v- X4 e% P* b+ D, s
/ x# f, z# O* P& ^: H1 R
此区块的难度值。这是当前区块挖矿难度的度量值(此处不对此概念的细节和计算作介绍)。
' T, k% x/ j9 q* ?3 ^
. f) m5 h* d/ y6 K) }+ unumber
7 ~$ g6 p6 B0 N" h$ i/ I% z, d: G; k
前序区块的总数。这标示了区块链的高度(即区块链上有多少区块)。创世区块的 number 为 0 。
) m% C; w0 H: b2 {" h' K% Z/ L2 E' T1 t* \  u8 M& w% ^1 q/ p) R
gasLimit
; I  M8 w: W" W8 A! j1 r$ B3 z0 f6 y$ B/ n1 u3 e3 y! V7 y9 S+ ^
每一个交易都需要消耗 gas 。gas limit 标示了该区块所记录的所有交易可以使用的 gas 总量。这是限制区块内交易数量的一种手段。5 `3 x0 F9 J( L4 B5 `! h

  p+ a! {8 \1 x1 b8 H  h4 m2 G8 r) RgasUsed, G3 p- H) n/ l0 `1 `  K$ k
! W" n/ m2 G2 r6 t5 z
区块中各条交易所实际消耗的 gas 总量。
+ m7 {6 y, v. ~2 n% N
/ c" i. F' h! W9 \timestamp
8 O: m, t( h3 b& t6 w
: G4 B  U, y' F( f区块创建时的 Unix 时间戳。谨记由于以太坊网络去中心化的特性,我们不能信任这个值,特别是撰写智能合约、涉及到时间相关的商业逻辑时不能依靠这个值。
3 X4 s. {  F" r/ y) k
9 O1 S) G" _# Z- |: \extraData: t& E) y5 K! ^* ?5 f

4 B% Z0 [4 S" P* n8 K% |能输入任何东西的不定长字节数组。当矿工创建区块时,可以在这个区域添加任何东西。. H* m+ c5 k% E- T# k1 z$ O

& f8 B: D6 ?* K' Q" C% z% h8 x2 [mixHash
- V8 w) h7 ?9 N4 n5 k& e8 t" ~
4 a" [% w, e! S# X用于验证一个区块是否被真正记录到链上的哈希值(如果想要真正理解这个概念,建议阅读这篇文章 Ethash proof-of-work function )。( E: ^5 {8 }8 u+ r

* c- B9 S' H" F# @% Enonce( \! S3 Q' m+ @! ?* M5 n3 O9 k

9 r9 P3 S+ c  J" a4 [和 mixHash 一样,用于验证区块是否被真正记录到链上的值。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

olwww 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1