Hi 游客

更多精彩,请登录!

比特池塘 区块链前沿 正文
默克尔树/ U6 Y7 r% d, Q! ^! M# h
7 h2 B+ ~/ b- R$ Z' e
在讨论以太坊的主要数据对象之前,我想先向各位简要介绍一下默尔克树到底是什么,以使得它得以发挥作用的属性特征。* c2 S' W2 `' Y4 C0 ~& b

: n$ x2 N4 n6 J' W( F. e" C黄皮书中假设由定制的默克尔-帕特里夏树维护世界状态和交易。附录 D 描述了这个数据结构。( P- H- M0 H+ b9 @& Z: B
9 a- n2 ]% z" X1 ^* ?
默克尔-帕特里夏树有许多有意思的属性,如果你想更深入地了解其在以太坊中的应用,我推荐你阅读这篇文章。
1 [. I6 e3 e5 j5 J0 Y* e. v
' o' F- i( H" B在默克尔树中,由叶子节点保存区块数据的哈希,而由非叶子节点保存其子节点的哈希。
: S( z. W/ ^: e, n! a; ^& g2 }( M1 ^) v. S: U) e2 P8 a/ O/ ?
-默克尔树示意图(包括节点以及他们之间的关系)-+ N1 K5 f3 y1 K( I% }

( r1 h5 p; X7 d  @默克尔树所指向数据的任何改动都会引起节点哈希的变化。由于每一个父节点中所保存的哈希值都取决于子节点所包含的数据,所以子节点中数据的变更都会引起父节点哈希的变化。并且这样的影响是连锁反应,从叶子节点直达根节点的。因此对叶子节点所指向数据的改动会引起根节点所保存哈希的变化。由上述结构特征,我们可以引申出两条重要的属性:3 C& K0 M# e, P7 i
. ~. V& ^, x& d1 C2 z
在判断两棵默克尔树所指向数据是否完全相同时,我们不需要比较每个叶子节点,而只需比较根节点所保存的哈希。
) C( B+ _' ~) x" N3 ~4 n6 i9 X
% k. {, q1 d0 P2 F/ o6 i+ @在判断特定数据是否被树所指向时,我们可以使用 默克尔证明 技术。此处不对该技术作过多介绍,只需知道这是证明数据存在于默克尔树中的一种简单、高效的方法。6 b, v8 \3 Q- N' L7 D6 n  a) g

* t. k/ `2 ], V  S. w7 [: W' Z1 y+ L第一种属性的重要之处在于,我们能够仅利用根节点的哈希值,就标示某一时刻整棵树所指向的数据。这意味着仅通过保存根节点的哈希值就能标示区块(无需储存区块链中所有的数据),且维护数据的不可篡改。" Z& F1 e/ p+ ~+ Z8 M2 C
0 J9 n3 R- M: p) ?8 [
至此我们理清了默克尔树中根节点哈希的作用,下面来介绍以太坊中的主要对象。
9 H- H7 u* @* A/ q7 f3 X5 Z
4 H( U7 b& K- B( b/ D! f5 P世界状态
6 [1 ?  D8 I5 m( K# j7 k* F
  K6 L4 ]6 Q0 I; l$ s+ J# m世界状态是地址(账户)到账户状态的映射。虽然世界状态不保存在区块链上,但在黄皮书的描述中,世界状态也由树来保存数据(此树也被称为状态数据库或者状态树)。世界状态可以被视作为随着交易的执行而持续更新的全局状态。以太坊就像一个去中心化的计算机,世界状态则是这台电脑的硬盘。
: s2 F9 a  U( \# X9 j* e: F
* ?4 ~  i( l3 Y6 Y* R以太坊中所有的账户信息都体现在世界状态之中,并由世界状态树保存。如果你想知道某一账户的余额,或者某智能合约当前的状态,就需要通过查询世界状态树来获取该账户的具体状态信息。下文中我也会简要介绍这些信息是如何存储的。- d- e0 Z: z1 E5 O7 J

1 R) Y1 U* ~: S-世界状态树与账户存储-& w* q8 l9 f3 r& g

: t9 c1 W) o$ K-世界状态树与账户存储-- T& v% [4 J/ R

+ X* ]1 q  C& u5 m: t# o账户状态
. Q: H8 W% O0 N+ v2 J! u. @4 @# D; i; ^+ _  A' \" m
以太坊中有两种账户类型:外部所有账户(Externally Owned Accounts 简称 EOA)以及合约账户。我们用来互相收发以太币、部署智能合约的账户就是 EOA 账户,而部署智能合约时自动生成的账户则是合约账户。每一个智能合约都有其独一无二的以太坊账户。
/ R! R7 e8 H8 g. E5 v  g
4 P- D# k& k1 {, k8 i8 b账户状态反映了一个以太坊账户的各项信息。例如,它存储了当前账户以太币的余额信息、当前账户发送过的交易数量…每一个账户都有账户状态。) o3 W8 P7 ^. r/ N7 ]2 F
  d& t% f- Z9 g( I! B& G' V
下面就来看看账户状态中都包括什么:
' h9 l+ }, y- l8 c
7 K$ X" y. b: ?3 B7 k9 N' a0 Nnonce% }# i) o& b# S2 @2 p! N
0 G3 }, A) P8 b4 g
从此地址发送出去的交易数量(如果当前为 EOA 账户)或者此账号产生的合约创建操作(现在先别管合约创建操作是什么)。; X  t& ?. @+ d/ q
' @6 ]/ ]9 h+ o) _1 b; s; C
balance: T( F# L- e' j4 U# G% ?# w. m& V5 V
/ r, d& S2 E( U% S- v* e& r/ w
此账号所拥有的以太币数量(以 Wei 计量)。
4 z. h/ ^' J6 t! v% J% ~2 X% ]  F3 q- L) p0 ]+ w
storageRoot% _, y5 t3 V$ I- c% ]% F

- h/ ~6 P6 f4 {3 Q, K" a账户存储树的根节点哈希值(稍后介绍账户存储是什么)。+ H: Y+ p' W) N0 q! u
% K4 t/ R3 F7 q3 U( x
codeHash8 A7 F! P. h; {3 ]

9 \9 {1 {3 n1 m. z1 p* @5 O对于合约账户,就是此账户存储 EVM 代码的哈希值。对于 EOA 账户,此处留空。* Z) U5 B. [" |: o" Q
2 f6 P+ K0 G% n/ v
账户状态中不容忽视的一个细节是,上述对象在内的所有对象都可变(除了 codeHash)。举例来说,当一个账户向其他账户发送以太币时,除了 nonce 会增加,账户的余额也会相应改变。
. W" Q$ n6 P7 [5 B
- @' R9 g3 B9 ^8 e而 codeHash 的不可变性使得,如果部署了有漏洞的智能合约,也无法修复更新此合约。对应的,只能部署一个新合约(而有漏洞的版本会一直存在于区块链上)。这也是为什么使用 Truffle 进行智能合约的开发和部署十分必要,并且用 Solidity 编程时要遵循 最佳实践 的要求。, t2 [" h8 e/ e

. r. e0 e( X0 a# \4 c2 X3 B) N! \账户存储树是保存与账户相关联数据的结构。该项只有合约账户才有,而在 EOA 中, storageRoot 留空、 codeHash 则是一串空字符串的哈希值。所有智能合约的数据都以 32 字节映射的形式保存在账户存储树中。此处不再赘述账户状态树如何维持合约数据。如果读者对其内部实现感兴趣,强烈建议阅读这篇文章。账户状态中的 storageRoot 区域负责维持账户存储树根节点哈希值。  V) `" I( W' }# o6 i' P
0 d9 U2 U# o2 y# ?! u
-账户状态与账户存储树-
0 _: D' }7 u% \( }2 e" K; @( u* j+ @) |* W
交易. \, d3 M1 \9 |% b' ~

* U; w7 H$ p2 Z$ p交易推动当前状态到下一状态的转变。在以太坊中有三种交易:
0 _, |; ~/ s: D8 h9 q3 R" s' l
EOA 之间传输值的交易(例如,改变发送方和接收方余额大小)。
  U' }2 _7 I. l. k1 R" ]8 }9 f! i5 ~9 t0 `% D
发送消息来调用合约的交易(例如,通过发送消息调用来触发 setter 方法,以设置合约中的值)。
% z& U- ^8 _) W( U8 S: ~) ]3 F; w& V/ @$ q) I2 Y$ Q* p& J
用于部署合约的交易(由此创建了合约账户)。
% }5 T7 o2 ~0 E
+ n6 L3 N2 l' p: ]4 S(从技术角度来讲,前两种交易是一样的…它们都是通过消息调用来改变账户状态的交易,只不过一个是 EOA 账户,一个是合约账户。此处将交易分为三种是为了方便读者的理解。)
2 W( E) Q  I7 o0 q  r$ N, _/ a7 i) \9 _) }
交易由以下部分组成:0 m0 R: g; a, e! u% s

7 B# M; j" i+ w& ^nonce
" r+ Z, s% O' B( s8 ^6 J5 G5 d  R9 w) X) ~, S  ^
此账户发出的交易序号数(校对注:可以粗略理解为“这是该账户的第几笔交易”)。
2 k4 K( U8 y& N7 P1 k) y# m5 O! o3 M1 L+ M3 p) ^/ W) w
gasPrice
5 r, o/ I7 |; r7 M. B+ Z# C+ t8 l8 }1 i% O2 |) Y5 J
执行此交易、进行计算时为每单位 gas 所支付的费用(以 Wei 计量)。6 N1 i( `' S! M8 a+ o( ?0 k( e% J" w
8 Q! J; j6 N- T5 M
gasLimit
6 x2 t. D) l, b+ r- G: T+ e6 P2 _5 N( e
执行此交易时可以使用的最大 gas 数量。8 g) G4 H* V% P: t$ H% W" I% l
1 x$ ]+ d. }& }, t
to
3 Y2 o; b4 `6 p1 n3 j5 A8 S6 w; z$ o  T
如果此交易用于传送以太币,此处为接收以太币的 EOA 地址。
. g3 z5 [$ @4 c. F
2 l% m  _, `& c; [1 s如果此交易用于向合约发送消息(例如,调用智能合约中的方法),此处为合约的地址。4 e: N$ k8 @# T+ Q* {& m
5 e4 m* I5 r# G2 s
如果此交易用于创建合约,此处值为空。- A- n! u3 g2 s2 M8 p# E  h

9 {( s0 H; t0 t: n, @0 Evalue
- ~6 j& e( Q" |6 l$ k9 C$ x& r+ \8 H7 ~; d5 W+ b
如果此交易用于收发以太币,此处为接收账户以 Wei 计量的代币数量。8 k8 k  ^# v; H7 {; A. |

& g0 s; `0 K- z( q如果此交易用于发送对合约的消息调用,此处为向接收此消息智能合约所给付的 Wei 数量。$ n- ~4 C5 I. J9 [8 p
# {/ N: n- A& ~* ~* W
如果此交易用于创建合约,此处为合约初始化时账户存放的以 Wei 计量的以太币数量。
. ^1 ^6 d+ w7 |8 u* x( S& ~' }# |' _6 L. n  a8 A! o2 x5 |. H
v, r, s
& ]. C9 F9 @9 p1 j8 E( l
5 B- M+ D* J. ]  s1 T3 n2 {在交易的密码学签名中用到的值,可以用于确定交易的发送方。! Z- W. e  M$ s1 e. N
% T3 z/ n/ g% L  S: L( N1 D
data(只用于价值传输以及向智能合约发送消息调用)
  ]  o3 u0 \6 b. `" l4 m6 A6 F7 l% y: i' d3 ?$ a
发送消息调用时附带的输入数据(例如,假设你想要执行智能合约中的 setter 方法,数据区就应该包括 setter 方法的标识符,以及你想要设定的参数值)。# j  m4 C& ]6 N% r
4 s) J7 {# b/ u% E( c
init(只用于合约创建)
" j3 t3 m, h- c* ]5 O, z6 g8 J
! F9 n& U8 ~& T用于初始化合约的 EVM 代码。
3 h% v5 Y/ N$ Q8 R
3 N. d: ?, Y8 f* k别想着一下子就把这些概念消化完… 必须对以太坊的内部机理有更深的认识才真正理解、使用像 data 区、init 区这样的概念。. o4 o. ]$ J5 N6 M, G6 Y; a1 W0 A

, Q% X( O$ U. c  n: w) R相信不出你的意料,区块中所有的交易也是存储在默克尔树中的。并且这棵树的根节点哈希值由区块头保存!下面我们就来剖析一下以太坊区块结构。
" ?1 }+ T# ~+ N$ W8 x$ D5 M; C" q8 Z
) D& G; _% M# B& f  L  s6 h6 p区块
9 \4 q' u$ \% J3 H/ t
9 Y% Q" N/ F/ f; Q8 u' F区块分为两部分,即区块头和区块体。6 f7 ]6 }2 p/ v) e% {

+ [) K" Y, o  H; V5 r6 Q* n区块头就是以太坊中的区块链部分。它保存了前一个区块(也可称为父区块)的哈希值,通过区块头的连接形成了一条由密码学背书的链。: r, Q! Z) S0 p$ _! k

( I/ T' m$ c$ w: S0 ^区块体包含了此区块中记录的一系列交易,以及叔块(ommer)区块头列表。如果想要进一步了解叔块,我推荐阅读这篇文章。
2 P5 i2 E; |3 X# [  a0 F
3 h5 R. f/ z9 Q' T-以太坊区块的抽象示意图-  ~0 F% k% K$ W& A; P0 u
# E0 e8 J7 n$ u$ \( S
下面就来介绍区块头包括哪些部分。
6 m% C, x0 h" ~9 f4 P+ ^0 X* Q7 @% R- a  p: l. Q. k
parentHash( a0 r# J6 ?/ }9 d
7 P6 }- R( }% |
前一个区块的区块头哈希值。每个区块都包含前序区块的哈希值,一路可回溯至链上的创世块。这也就是维护数据不会被篡改的结构设计(任何对前序区块的篡改都会影响后续所有区块的哈希值)。( ?# N+ v- V4 \
& w) _3 H1 R0 {1 U  q3 E
ommersHash
9 y- [$ c) N* @: P; V  d0 a- O5 }( F+ U9 r, N- ~' T
叔块头以及部分区块体的哈希值。; f: b+ @' q# y& [+ l' a
' b2 @$ p) q) ^3 u& N2 ]
beneficiary
  O+ N0 R( l3 O% ]$ L3 {3 m9 C  E3 Q6 E1 j7 v
因为挖到此区块而获得收益的以太坊账户。* o9 ?. X) R1 t/ P: y8 f5 l
  ]0 j% ]. a  n: I6 A3 C, C
stateRoot
: s# W* Y. T' ~+ R0 r; M3 ?/ v9 l* n: f! \2 D2 g2 f* N9 C% y8 |
世界状态树的根节点哈希值(在所有交易被执行后)。0 |1 B! S$ W) R

! r' w  w0 B( A# k* N* ~transactionsRoot
4 R7 o# T+ {' A* y6 O. {- S' G1 J; s) F0 y
交易树根节点的哈希值。这棵树包含了区块体的所有交易。6 u) S2 i" y# `% t5 L

$ h4 V, Z4 g0 F0 v6 Z+ creceiptsRoot6 o8 L' a, x* l" r
) U1 w5 B5 ?: P# B  H" s8 Z
每当交易执行时,以太坊都会生成对应结果的交易收据。此处就是这个交易收据树的根节点哈希。; d; ]# ]* @( b( O# }

) ]8 T) b) k) c7 _% GlogsBloom
9 n8 r% m# X& p- w) Z7 j6 v" F9 ]- Z
布隆过滤器,用于判断某区块的交易是否产生了某日志(如果对这方面感兴趣,可以查阅 Stack Overflow 的这个答案)。这避免了在区块中存储日志信息(节省了大量空间)。8 Z+ B  h6 y6 p6 H& s. i1 O

9 T( _1 d" ~9 @$ X) {difficulty, B% Y6 Y6 ~5 E5 O

% `5 c# b2 {9 I此区块的难度值。这是当前区块挖矿难度的度量值(此处不对此概念的细节和计算作介绍)。6 v% |; B9 L" f
& V* G1 r& Q. U, G7 _
number
" I2 S" }  j) P; i1 s/ l- ^# z. @
前序区块的总数。这标示了区块链的高度(即区块链上有多少区块)。创世区块的 number 为 0 。
0 c; O# L% n6 H/ x: \2 B( E( }+ _: {: S# e. o' Q* {
gasLimit
9 p9 @# n$ y" S0 S9 j. }1 ?/ M4 Y' @& K3 z6 `8 ~8 x2 T2 O) m& m/ [
每一个交易都需要消耗 gas 。gas limit 标示了该区块所记录的所有交易可以使用的 gas 总量。这是限制区块内交易数量的一种手段。+ }- c) R) K  R  L& a
$ Y5 j) c$ _$ |4 X$ I* s8 U
gasUsed
; ~6 D5 t( P  D. N+ G- L/ `  j+ U
9 [( _6 K" ?) k. z- Z区块中各条交易所实际消耗的 gas 总量。
0 I0 ^- N% R7 b
6 s5 p6 L. }; g8 Ytimestamp
. C. |  U6 L" [6 k8 t5 c% \1 d, l/ w7 f& l
区块创建时的 Unix 时间戳。谨记由于以太坊网络去中心化的特性,我们不能信任这个值,特别是撰写智能合约、涉及到时间相关的商业逻辑时不能依靠这个值。
% G$ G& Z0 N' j, B
4 Z! O, M2 c" f5 z# {extraData
# s8 h, i( R) p. F0 O
# b% @+ B  V4 T+ d能输入任何东西的不定长字节数组。当矿工创建区块时,可以在这个区域添加任何东西。: |' W! ~5 M% r5 G
+ v% k; c" E7 q2 Z# ?2 |$ o
mixHash0 C, R& K7 Y+ k* T4 e9 C) A9 E2 k
; N2 C; w+ ?$ ]
用于验证一个区块是否被真正记录到链上的哈希值(如果想要真正理解这个概念,建议阅读这篇文章 Ethash proof-of-work function )。
2 ]& z% \* }. m& W0 @, j+ H! Z% Z. H
' d- `7 d2 o0 ~3 v6 X! z# vnonce
% g( e8 H6 }! f8 b
- M& q5 X! |' b- ]3 s2 F0 S和 mixHash 一样,用于验证区块是否被真正记录到链上的值。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

olwww 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1