Hi 游客

更多精彩,请登录!

比特池塘 区块链前沿 正文
默克尔树8 ~5 H7 q& U9 R
" L) m7 G* d  |. t
在讨论以太坊的主要数据对象之前,我想先向各位简要介绍一下默尔克树到底是什么,以使得它得以发挥作用的属性特征。
( O" g7 w( Q1 Q3 T$ i1 r* `5 J' m6 d( M$ w# K6 _
黄皮书中假设由定制的默克尔-帕特里夏树维护世界状态和交易。附录 D 描述了这个数据结构。# H* Q; \$ |: A- H% _9 @' k$ D/ {4 @

2 \! V9 S) b  A; i默克尔-帕特里夏树有许多有意思的属性,如果你想更深入地了解其在以太坊中的应用,我推荐你阅读这篇文章。
4 y3 u2 v, [: r* F6 S
/ I4 J7 H( F  A# v在默克尔树中,由叶子节点保存区块数据的哈希,而由非叶子节点保存其子节点的哈希。
; B) P7 D: U+ z: s. H! Q; C4 Z5 n( E1 [% v6 q2 @% o
-默克尔树示意图(包括节点以及他们之间的关系)-9 x  [! E* f" J% {

5 V' h2 i+ ~: C7 a默克尔树所指向数据的任何改动都会引起节点哈希的变化。由于每一个父节点中所保存的哈希值都取决于子节点所包含的数据,所以子节点中数据的变更都会引起父节点哈希的变化。并且这样的影响是连锁反应,从叶子节点直达根节点的。因此对叶子节点所指向数据的改动会引起根节点所保存哈希的变化。由上述结构特征,我们可以引申出两条重要的属性:* v7 o" t, k( b6 i
. o0 l7 L7 f6 `; i
在判断两棵默克尔树所指向数据是否完全相同时,我们不需要比较每个叶子节点,而只需比较根节点所保存的哈希。' L2 @3 F* m2 V( v7 |
, }5 o, z& y+ @) i/ A5 p+ H
在判断特定数据是否被树所指向时,我们可以使用 默克尔证明 技术。此处不对该技术作过多介绍,只需知道这是证明数据存在于默克尔树中的一种简单、高效的方法。
6 o6 m# ]2 ]1 M$ H! u9 T  n3 `: l1 w* m* M% w0 A6 X
第一种属性的重要之处在于,我们能够仅利用根节点的哈希值,就标示某一时刻整棵树所指向的数据。这意味着仅通过保存根节点的哈希值就能标示区块(无需储存区块链中所有的数据),且维护数据的不可篡改。8 E# L: K% A9 a- V7 g/ M, i; }
0 W3 V# u: Z5 O- s
至此我们理清了默克尔树中根节点哈希的作用,下面来介绍以太坊中的主要对象。3 ?. w8 Y: R; @, m- z

+ g4 v" ~: k$ s) T  q) Y- \& J4 U世界状态" e; r8 E0 X3 P. V, |9 E9 n
4 U/ W; R; {7 |, {5 s7 b0 t
世界状态是地址(账户)到账户状态的映射。虽然世界状态不保存在区块链上,但在黄皮书的描述中,世界状态也由树来保存数据(此树也被称为状态数据库或者状态树)。世界状态可以被视作为随着交易的执行而持续更新的全局状态。以太坊就像一个去中心化的计算机,世界状态则是这台电脑的硬盘。3 s( _. p+ i0 X) z) F
* p8 O! C6 P- T9 Q2 K, {) \  r
以太坊中所有的账户信息都体现在世界状态之中,并由世界状态树保存。如果你想知道某一账户的余额,或者某智能合约当前的状态,就需要通过查询世界状态树来获取该账户的具体状态信息。下文中我也会简要介绍这些信息是如何存储的。
$ o! y& J' ?3 [
5 U1 l  }. }5 E$ W6 M-世界状态树与账户存储-
0 [3 x# j% ~- \0 ?# {6 w& ?% x% u( J# F* ?* O
-世界状态树与账户存储-; A: w( B1 [+ o

! u9 l* X  o) W" Z: K& V账户状态5 b; c# v* O- M: g9 N
  ]4 Q% V6 J" O% r6 U1 R
以太坊中有两种账户类型:外部所有账户(Externally Owned Accounts 简称 EOA)以及合约账户。我们用来互相收发以太币、部署智能合约的账户就是 EOA 账户,而部署智能合约时自动生成的账户则是合约账户。每一个智能合约都有其独一无二的以太坊账户。. I+ l% T( y& f7 w& A

+ a% Z. _, Q' R  j( d; d账户状态反映了一个以太坊账户的各项信息。例如,它存储了当前账户以太币的余额信息、当前账户发送过的交易数量…每一个账户都有账户状态。9 ^$ B2 N- X% G4 E# [
6 P( C; i( k- l4 `
下面就来看看账户状态中都包括什么:
3 X) s3 G# L8 p! w3 v. Z9 S& a4 o& @2 K5 ^  E2 {6 X1 {
nonce! W* o$ A2 w! f1 M' ^! L

% \! F, t9 {* y9 V从此地址发送出去的交易数量(如果当前为 EOA 账户)或者此账号产生的合约创建操作(现在先别管合约创建操作是什么)。
. y; S( _' H6 }$ _, t; n
$ F" @! f/ h- r# ~/ X! @  G" `balance
* Y6 Q, n) w3 W2 T( z* r) t" R! N( Q4 L. j
此账号所拥有的以太币数量(以 Wei 计量)。
( o% L2 C% C$ {  y& O5 v: k7 T5 ^' B$ n  O2 g
storageRoot4 C" v/ S2 t* ]! S3 ~1 X, ]
; b5 Z+ n) [# i3 k8 L) i
账户存储树的根节点哈希值(稍后介绍账户存储是什么)。
* h# y- _' @) h+ B' t  L. P7 X/ B1 N* A" ^) V
codeHash  Y" O4 y! n, ?( D$ g6 ^
* Y" L8 a! X6 O  D$ t
对于合约账户,就是此账户存储 EVM 代码的哈希值。对于 EOA 账户,此处留空。
- ]! B2 L1 I1 k' l0 m3 J2 v
- v( r1 R: s) m9 _+ W* p账户状态中不容忽视的一个细节是,上述对象在内的所有对象都可变(除了 codeHash)。举例来说,当一个账户向其他账户发送以太币时,除了 nonce 会增加,账户的余额也会相应改变。' h, ]+ X- ~! G( w- |6 M" r' w* Y
  n' V9 Y6 V7 b9 m& Z( N
而 codeHash 的不可变性使得,如果部署了有漏洞的智能合约,也无法修复更新此合约。对应的,只能部署一个新合约(而有漏洞的版本会一直存在于区块链上)。这也是为什么使用 Truffle 进行智能合约的开发和部署十分必要,并且用 Solidity 编程时要遵循 最佳实践 的要求。
( z; k3 u' p9 [4 _9 ~8 _9 ]4 y* d- B4 q! e! F
账户存储树是保存与账户相关联数据的结构。该项只有合约账户才有,而在 EOA 中, storageRoot 留空、 codeHash 则是一串空字符串的哈希值。所有智能合约的数据都以 32 字节映射的形式保存在账户存储树中。此处不再赘述账户状态树如何维持合约数据。如果读者对其内部实现感兴趣,强烈建议阅读这篇文章。账户状态中的 storageRoot 区域负责维持账户存储树根节点哈希值。- g" b) y6 k, R  d' g: N/ h8 I
" X8 I. v9 F& Z& a
-账户状态与账户存储树-" h4 I6 S# }  ^- L' q

( h0 c3 J) y5 K' B交易
, p. N0 U; l/ U) u7 L
# l6 A/ s% P, F0 i9 C% B! [  C交易推动当前状态到下一状态的转变。在以太坊中有三种交易:. U2 S& ?" T1 |/ X

* o6 F( E0 s  L, P+ o2 t% FEOA 之间传输值的交易(例如,改变发送方和接收方余额大小)。+ \# }# n- L4 N& e: ^( v

2 e. L/ `2 L* p5 m" a发送消息来调用合约的交易(例如,通过发送消息调用来触发 setter 方法,以设置合约中的值)。) ~9 _( L  C0 A& n9 ?& d

% U2 A1 S0 f% A* k1 W3 v: K8 N  y& m$ P用于部署合约的交易(由此创建了合约账户)。
# G0 o! m1 Z  u! C0 @
+ ^' J8 M' z9 ]* S3 g(从技术角度来讲,前两种交易是一样的…它们都是通过消息调用来改变账户状态的交易,只不过一个是 EOA 账户,一个是合约账户。此处将交易分为三种是为了方便读者的理解。)' N" b/ {) R, q0 |0 {4 ?& y5 |

% n9 I: ~$ y8 `* V/ g# i交易由以下部分组成:
  w, J- p9 \) ~5 ]: r2 h# @( l# G( ~# E" j: o% B
nonce/ x2 E: g4 b, V% U& o

: i0 N# i! U% L: A: X$ Z8 Y$ L此账户发出的交易序号数(校对注:可以粗略理解为“这是该账户的第几笔交易”)。
+ ?. m% v' A( W6 ~. x7 [
6 y8 X* [; F/ k; ~0 J1 m" WgasPrice( F: z  H4 s$ K7 ~) P- I

/ Y0 [, e& K/ t. A- u$ R$ ^执行此交易、进行计算时为每单位 gas 所支付的费用(以 Wei 计量)。: u' `. C" [( ]& Z# Q) Q- R
) I1 J4 I6 R/ i1 I. L
gasLimit
, k" n# l; z, E% Q3 Q6 E! |, V0 b5 |; O* _$ i8 ?3 q
执行此交易时可以使用的最大 gas 数量。
) s5 e# o! E) A. y" Z: X- j" C: d) c- q; h/ W+ {1 t
to" k  `# I# s3 t* s9 F! q

: s# K" K) Z: I2 K$ l. S如果此交易用于传送以太币,此处为接收以太币的 EOA 地址。" X0 o8 D) R' V+ T, I2 C0 S
) r- a& H/ z( j! i5 W+ z6 |
如果此交易用于向合约发送消息(例如,调用智能合约中的方法),此处为合约的地址。; q0 X1 H! [+ B6 r

- f- ~3 S& C1 @5 g5 P* a* f如果此交易用于创建合约,此处值为空。' `, ^% k$ h( z' m
' s- w1 U. C3 b/ Q
value
5 Z+ H( q: z8 ]; O% d8 Q, d+ n
# p8 F3 a- W+ W8 u. m如果此交易用于收发以太币,此处为接收账户以 Wei 计量的代币数量。
  k4 B8 Y1 v3 i' D# l( Q/ |. E
: t! i) W& a/ v( X如果此交易用于发送对合约的消息调用,此处为向接收此消息智能合约所给付的 Wei 数量。
; N( \; l6 y/ X; \$ C  F/ |+ w
4 b& N9 B$ B6 g如果此交易用于创建合约,此处为合约初始化时账户存放的以 Wei 计量的以太币数量。
: L. S0 j( ~. S% h. q) e1 ?& y& s4 n/ F0 ?
v, r, s+ g( Q6 C  b  Z8 z8 m
% F$ T* B$ `; X1 j4 |
在交易的密码学签名中用到的值,可以用于确定交易的发送方。, O6 X" {0 H. N6 y" d

/ g$ h$ e+ x1 I4 E7 J+ j9 q" Idata(只用于价值传输以及向智能合约发送消息调用)0 ]* h, |) k$ ?2 K; H

6 N% R& ]" W+ I, ?0 O& p9 u6 \发送消息调用时附带的输入数据(例如,假设你想要执行智能合约中的 setter 方法,数据区就应该包括 setter 方法的标识符,以及你想要设定的参数值)。
, e* S- B! B# G
, l" m4 }5 z; t8 Ninit(只用于合约创建)
; A1 @  P+ {2 D! l7 A- r! x3 z! q, q$ G* m* u6 t7 F& n
用于初始化合约的 EVM 代码。
! L) c1 l: ?! ^4 A# i& L3 K2 M" D( |4 @7 Q- F) X
别想着一下子就把这些概念消化完… 必须对以太坊的内部机理有更深的认识才真正理解、使用像 data 区、init 区这样的概念。; }0 O. [( k. t( ?; k

8 c! c. F" n) o0 L' y6 g$ z相信不出你的意料,区块中所有的交易也是存储在默克尔树中的。并且这棵树的根节点哈希值由区块头保存!下面我们就来剖析一下以太坊区块结构。2 \, W% R9 h# E" b8 Y" K. p7 X
/ `4 w0 ?" k  f% y/ |8 n
区块! l' ]4 S9 z) a1 }5 P' ~

( J2 L+ ?4 a% G& M; O# s区块分为两部分,即区块头和区块体。( H) f+ d) q8 i# i/ p" U* z" W7 k$ u: D" O
) D$ V0 l+ z  \
区块头就是以太坊中的区块链部分。它保存了前一个区块(也可称为父区块)的哈希值,通过区块头的连接形成了一条由密码学背书的链。
  ^5 t& }2 W. f2 [% p  r# N$ l; n$ C( h; ~* S$ y' s  D5 V5 I
区块体包含了此区块中记录的一系列交易,以及叔块(ommer)区块头列表。如果想要进一步了解叔块,我推荐阅读这篇文章。  m: @; E! p! ]9 S7 U

  O  w- f6 ]8 W  ~1 r; Y* B-以太坊区块的抽象示意图-3 g% C9 E  l4 M1 n
) N) u" d3 M* w0 v" F1 R
下面就来介绍区块头包括哪些部分。6 v! T  b8 J' a: D# h
1 B% ?8 Z! V1 H2 a6 {: ^
parentHash
# i% _5 P! g. ]5 m; T! g3 e) u) T' g7 d& `
前一个区块的区块头哈希值。每个区块都包含前序区块的哈希值,一路可回溯至链上的创世块。这也就是维护数据不会被篡改的结构设计(任何对前序区块的篡改都会影响后续所有区块的哈希值)。
1 j- E+ l9 `9 K0 M( x$ Y+ R1 Z1 I4 u8 V
ommersHash6 H) f% s9 J. ]& B$ W8 X
$ G. V. T$ s3 s# I
叔块头以及部分区块体的哈希值。6 g' q. a& I% `0 ^6 q
  Q) f- j7 }! c% Q
beneficiary* H1 p6 v# G" s- X: ^3 Y$ ^
% a' z- M8 W! n- n
因为挖到此区块而获得收益的以太坊账户。4 J) Z( O2 w3 H) r
- C6 d9 p: j1 h: i9 p
stateRoot
# E) Z7 N& s# X- S8 v$ u
$ ~* p# k/ l+ i: Y' _世界状态树的根节点哈希值(在所有交易被执行后)。
9 K. L; x0 E8 A/ t
9 U& o8 W$ A) _8 z' xtransactionsRoot
* g, G  R4 _* _4 S3 V7 t/ Q* ^( B$ L% _) L* Q' A
交易树根节点的哈希值。这棵树包含了区块体的所有交易。3 n- J) l$ |/ u
4 d; r* j& ?$ w& o: s% F- O
receiptsRoot0 p! Q7 h$ T4 e$ H$ e9 C

$ b  g8 b, |  v每当交易执行时,以太坊都会生成对应结果的交易收据。此处就是这个交易收据树的根节点哈希。
; A# o1 B4 a2 E' E' b: h
0 q! L" m( [1 v5 H& D# \0 S/ \3 n/ ~: wlogsBloom
' }7 @' c; @  P2 o4 z9 u3 _
' k/ s! A- G1 z- |' p布隆过滤器,用于判断某区块的交易是否产生了某日志(如果对这方面感兴趣,可以查阅 Stack Overflow 的这个答案)。这避免了在区块中存储日志信息(节省了大量空间)。0 f* Z3 k1 W) w/ {- K7 f  v

; n; X- J; Z) p0 `$ ~5 e, o3 i6 \2 `difficulty" ]4 \/ n3 A, j. u$ i
2 K; J, z6 o1 o! q
此区块的难度值。这是当前区块挖矿难度的度量值(此处不对此概念的细节和计算作介绍)。# p9 X% @: r  G+ e: H, ~
' m' N* G# A5 O, [
number
3 t* g0 G3 F( v+ L, h
- z5 H! {/ o  v: H) o前序区块的总数。这标示了区块链的高度(即区块链上有多少区块)。创世区块的 number 为 0 。' c& j0 `+ j/ z* c1 z  T3 a
$ U! U, H" m- j; {4 `) g2 b9 w
gasLimit: i: i* {! @+ `

" D3 M2 ]! l" j# }每一个交易都需要消耗 gas 。gas limit 标示了该区块所记录的所有交易可以使用的 gas 总量。这是限制区块内交易数量的一种手段。+ L- e; N* ?! J0 d+ _0 z9 I$ z2 O  p* _
1 j% P: K  ~9 t- w" W) R6 T
gasUsed% |$ k8 [1 _+ A' D# w* l
$ A& D6 e. H9 e! F$ A& O( T
区块中各条交易所实际消耗的 gas 总量。
- ?+ v' c6 d6 ^8 ~1 Z
$ @. f# O5 ^7 S7 T1 btimestamp
7 A* v7 M9 Z* o, G# V. a, ]" R
' I. Y/ G9 ]% ], Z; F区块创建时的 Unix 时间戳。谨记由于以太坊网络去中心化的特性,我们不能信任这个值,特别是撰写智能合约、涉及到时间相关的商业逻辑时不能依靠这个值。9 d0 d. P5 x& S) E) f3 e- O

2 y( h) Z$ Y4 o4 q* c7 A& `extraData% q" @; v! M$ ]- i

. F0 ^; u9 G, ^# P能输入任何东西的不定长字节数组。当矿工创建区块时,可以在这个区域添加任何东西。
8 G; ?' J' V+ G- m! e! o/ L1 Q
( x- D+ h% S  k! ?mixHash
; a* h5 k5 _  l
3 h- m( ?! @/ J6 z/ d用于验证一个区块是否被真正记录到链上的哈希值(如果想要真正理解这个概念,建议阅读这篇文章 Ethash proof-of-work function )。
: z9 q9 ]7 w9 ^* p" p, N
5 f# v1 N; @1 m' H; I) v7 x3 G' P$ u! rnonce
  S  W6 ?4 e0 J) C+ Z8 ]  V4 h7 K9 r. F3 K+ ]$ r( ]1 U2 |) [! ~* Y
和 mixHash 一样,用于验证区块是否被真正记录到链上的值。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

olwww 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1