Hi 游客

更多精彩,请登录!

比特池塘 区块链前沿 正文
默克尔树
( N* `7 g( @! }$ c( i6 U7 c2 e
8 u9 U8 l# {) t: w( w" y在讨论以太坊的主要数据对象之前,我想先向各位简要介绍一下默尔克树到底是什么,以使得它得以发挥作用的属性特征。* Q  g( c8 R3 ], F2 V" m
' h& @0 k6 E0 a' t; A. ~% s$ z
黄皮书中假设由定制的默克尔-帕特里夏树维护世界状态和交易。附录 D 描述了这个数据结构。
+ s0 `: h7 L9 y/ h; h$ D' ?/ r# z0 v+ h& q; r2 l
默克尔-帕特里夏树有许多有意思的属性,如果你想更深入地了解其在以太坊中的应用,我推荐你阅读这篇文章。
, p( t# T& T2 d- @+ Y/ u$ t
3 n: B* C1 {# i6 G' ?( Z在默克尔树中,由叶子节点保存区块数据的哈希,而由非叶子节点保存其子节点的哈希。
8 E( x- ?0 n  m0 o
9 G' z1 [# X) Q% t-默克尔树示意图(包括节点以及他们之间的关系)-4 r) S' X2 i( z
% N& R! l3 N* _* x( {% U
默克尔树所指向数据的任何改动都会引起节点哈希的变化。由于每一个父节点中所保存的哈希值都取决于子节点所包含的数据,所以子节点中数据的变更都会引起父节点哈希的变化。并且这样的影响是连锁反应,从叶子节点直达根节点的。因此对叶子节点所指向数据的改动会引起根节点所保存哈希的变化。由上述结构特征,我们可以引申出两条重要的属性:
: ]" D+ j3 s5 Y6 t3 {5 Q
/ s: h, E$ _: {0 @  m在判断两棵默克尔树所指向数据是否完全相同时,我们不需要比较每个叶子节点,而只需比较根节点所保存的哈希。9 I5 c/ ]5 R  w, Y5 J

8 l. `  c6 p4 y+ H在判断特定数据是否被树所指向时,我们可以使用 默克尔证明 技术。此处不对该技术作过多介绍,只需知道这是证明数据存在于默克尔树中的一种简单、高效的方法。0 ]) W. d3 a0 c$ k. A; q7 ^! K

* Q: m# z+ X+ t3 \* {# _第一种属性的重要之处在于,我们能够仅利用根节点的哈希值,就标示某一时刻整棵树所指向的数据。这意味着仅通过保存根节点的哈希值就能标示区块(无需储存区块链中所有的数据),且维护数据的不可篡改。+ Y/ }! p2 ?# `

: y: k* w* N8 r2 j+ z. n% o至此我们理清了默克尔树中根节点哈希的作用,下面来介绍以太坊中的主要对象。
$ ~2 E6 n8 M5 q& j. y/ X# C
; ?9 t' A. D) J世界状态
  h4 P4 |2 a; z" x6 Y2 `  m! F% w0 K! \$ H0 H6 C, ~9 t
世界状态是地址(账户)到账户状态的映射。虽然世界状态不保存在区块链上,但在黄皮书的描述中,世界状态也由树来保存数据(此树也被称为状态数据库或者状态树)。世界状态可以被视作为随着交易的执行而持续更新的全局状态。以太坊就像一个去中心化的计算机,世界状态则是这台电脑的硬盘。
  z1 J! G- H1 U1 `2 d8 J6 J1 ~% l2 |' o. g9 Y. {& X5 U
以太坊中所有的账户信息都体现在世界状态之中,并由世界状态树保存。如果你想知道某一账户的余额,或者某智能合约当前的状态,就需要通过查询世界状态树来获取该账户的具体状态信息。下文中我也会简要介绍这些信息是如何存储的。1 G1 Y" C$ V4 ]
6 R% i! }8 f9 Q1 s* ?
-世界状态树与账户存储-
, v" c" V2 [; q! K5 Q# I
$ _7 j% Z  q4 {8 a( F3 s-世界状态树与账户存储-
+ _% q/ A7 _, s. y" b2 b$ u
8 v0 u8 L! D0 l账户状态
, r$ d+ X" q. V6 E2 n8 M( a" @, Q+ y- b5 J+ q! }' Q
以太坊中有两种账户类型:外部所有账户(Externally Owned Accounts 简称 EOA)以及合约账户。我们用来互相收发以太币、部署智能合约的账户就是 EOA 账户,而部署智能合约时自动生成的账户则是合约账户。每一个智能合约都有其独一无二的以太坊账户。* q4 ~; v' K% k, s# i. |

' v7 ?# S1 [  ?8 [账户状态反映了一个以太坊账户的各项信息。例如,它存储了当前账户以太币的余额信息、当前账户发送过的交易数量…每一个账户都有账户状态。& J, y; P: E8 \$ O1 v0 l

: B/ c$ f% @2 v) w6 d$ ^下面就来看看账户状态中都包括什么:" j6 i# U0 N% C6 ^

( S9 v2 |* R1 a9 Dnonce
& M0 I0 |7 o; a. g  A8 x3 H6 m* l% I. |* Q2 A* t0 ~, ?# ^( {
从此地址发送出去的交易数量(如果当前为 EOA 账户)或者此账号产生的合约创建操作(现在先别管合约创建操作是什么)。
6 Z! I- h% u0 \" q  H. `* o5 Y0 W* N# c, }! l! e! Z  z/ L3 s+ k+ S
balance
2 E3 Q" c  z5 A9 x! t* f& J* A5 J( R" O6 ~; V( L0 ?- _, ?. L
此账号所拥有的以太币数量(以 Wei 计量)。1 B9 u$ Q2 I- M  T
' B& E) J. M  ^- V
storageRoot
( b+ o  z) x; E+ E- G8 d; w! a4 R! b0 W1 Y7 A( O
账户存储树的根节点哈希值(稍后介绍账户存储是什么)。5 p) @/ {" h- _" I6 p
$ a- `, ]1 M+ t/ O; Z( q
codeHash
0 \5 X, v  u, J
  ]  m' ?# f/ @! Y: }对于合约账户,就是此账户存储 EVM 代码的哈希值。对于 EOA 账户,此处留空。
. c& D* S3 E8 j3 N" \8 k) t; s2 F% ]; x
账户状态中不容忽视的一个细节是,上述对象在内的所有对象都可变(除了 codeHash)。举例来说,当一个账户向其他账户发送以太币时,除了 nonce 会增加,账户的余额也会相应改变。8 \8 o7 M! y4 x' V
8 s/ ^: f! Y* n+ s: d% x: j
而 codeHash 的不可变性使得,如果部署了有漏洞的智能合约,也无法修复更新此合约。对应的,只能部署一个新合约(而有漏洞的版本会一直存在于区块链上)。这也是为什么使用 Truffle 进行智能合约的开发和部署十分必要,并且用 Solidity 编程时要遵循 最佳实践 的要求。
1 @1 O- W: H: I
4 P# t' }% P# Y2 K5 O账户存储树是保存与账户相关联数据的结构。该项只有合约账户才有,而在 EOA 中, storageRoot 留空、 codeHash 则是一串空字符串的哈希值。所有智能合约的数据都以 32 字节映射的形式保存在账户存储树中。此处不再赘述账户状态树如何维持合约数据。如果读者对其内部实现感兴趣,强烈建议阅读这篇文章。账户状态中的 storageRoot 区域负责维持账户存储树根节点哈希值。
6 y) Z" x0 Y5 P& z4 E. L
/ Z4 M8 t7 r+ t-账户状态与账户存储树-
* n, z, Q- E8 a9 E% ?  X
- y9 S' }! @& [% d交易
! [2 t; X! D$ R8 W, ~* L8 _
1 z: t8 Z+ }6 ^, T: }" F交易推动当前状态到下一状态的转变。在以太坊中有三种交易:
9 r: ]# x" S: [. z: x8 Z. R2 L) e! L9 i2 O, R; b/ e0 K
EOA 之间传输值的交易(例如,改变发送方和接收方余额大小)。
7 {; F' _( j, p* X8 F" M+ e" b% L
发送消息来调用合约的交易(例如,通过发送消息调用来触发 setter 方法,以设置合约中的值)。
5 Y$ t# w# z7 L; p8 c, F1 i$ ^' ]0 _! f
用于部署合约的交易(由此创建了合约账户)。
& }1 l. Z% b$ d) w5 E" k. B' I, G& k. R
. p9 v/ E( O1 C(从技术角度来讲,前两种交易是一样的…它们都是通过消息调用来改变账户状态的交易,只不过一个是 EOA 账户,一个是合约账户。此处将交易分为三种是为了方便读者的理解。)
' b. [* L+ n( @. }8 {  n
+ A5 O$ G0 t6 m1 R交易由以下部分组成:
+ c1 {* z0 J5 v$ J' u" ]- Y& a4 b6 X2 C
. w0 m" x) Y8 j6 Z/ f0 J, P1 Pnonce
) K3 \4 S! T) a  X- S3 z5 B% J. p, c0 P, ]% I
此账户发出的交易序号数(校对注:可以粗略理解为“这是该账户的第几笔交易”)。
8 c2 y. }1 X$ D/ Z' p/ j5 `* `
  ]1 P7 j7 j7 v1 hgasPrice6 u5 @4 E6 l5 _0 b% n
$ u. z. v# o+ T% M  p6 r) B7 I6 r
执行此交易、进行计算时为每单位 gas 所支付的费用(以 Wei 计量)。$ _* |% b5 B7 k) x, k1 k

2 g9 p) p- Q+ egasLimit' h, M) [) F0 U# e: q; e, w

7 U% |# _- _# I+ x. N8 j执行此交易时可以使用的最大 gas 数量。
9 l7 G4 E8 l9 X& I: y8 F4 }6 l* g1 W2 o4 M1 C! m
to- u3 \$ m( }" ]% s4 C( b

& n8 j' g  K( l; Z. R( ^如果此交易用于传送以太币,此处为接收以太币的 EOA 地址。) C8 \& v$ a5 C1 i  C( K* h
; n1 L1 I% ^" A  C1 `. u3 T
如果此交易用于向合约发送消息(例如,调用智能合约中的方法),此处为合约的地址。
) ^: Y% P7 N# i  d" {
+ }$ s: }# F+ |3 b# a如果此交易用于创建合约,此处值为空。. _" x5 U3 j6 d* ]/ s% ]7 w4 J

4 J3 Q9 Y' b* Y! Y$ X" Zvalue
9 E$ y% q3 m, x' v
8 W- N! g% l8 _" M7 q  b如果此交易用于收发以太币,此处为接收账户以 Wei 计量的代币数量。
. X4 ?: Q8 k6 x" }, Z/ ~
" V! o" c; _5 ~: u% Q- _  ?+ I如果此交易用于发送对合约的消息调用,此处为向接收此消息智能合约所给付的 Wei 数量。
: Z: O: q, X% j5 X8 l6 N5 H6 y# Z
4 T8 u2 A' R1 C) \$ s( p' j5 Z如果此交易用于创建合约,此处为合约初始化时账户存放的以 Wei 计量的以太币数量。
( }- |+ V5 r- T, ^0 @0 w. R6 \" S) ]! Z& e! G5 ~
v, r, s5 [6 Q1 d5 q! Y# Z6 I  }% u

% ~) m& ]9 G  v' {& X在交易的密码学签名中用到的值,可以用于确定交易的发送方。& v' |$ `6 s( C+ q% V
* x% Q4 E  b* X6 J* \, a5 H
data(只用于价值传输以及向智能合约发送消息调用)
* r$ D/ P3 \) b# J
7 X0 L1 e$ G' J* r5 O! D3 d发送消息调用时附带的输入数据(例如,假设你想要执行智能合约中的 setter 方法,数据区就应该包括 setter 方法的标识符,以及你想要设定的参数值)。
3 T8 R# z+ j" m( H  I) q) h
/ T7 k. P0 A. o, o! T9 Zinit(只用于合约创建)) ]. o3 |. i4 ^* c! _6 ~
, B- E1 @- M8 {% E
用于初始化合约的 EVM 代码。9 S' o3 P; V- w4 \8 |9 \6 G
3 f6 z9 y4 h; v  H" ~8 _, F
别想着一下子就把这些概念消化完… 必须对以太坊的内部机理有更深的认识才真正理解、使用像 data 区、init 区这样的概念。1 L2 s+ X! E: a! j: }: q4 m6 ~  ^
! i9 O* O* @7 u3 b2 j
相信不出你的意料,区块中所有的交易也是存储在默克尔树中的。并且这棵树的根节点哈希值由区块头保存!下面我们就来剖析一下以太坊区块结构。
+ H: J% A5 R. F7 p# Q2 m# R& V7 r6 n' _; _# u$ G
区块
) J! f0 F0 |2 C
! [  \$ ?5 I1 E* l" o区块分为两部分,即区块头和区块体。1 h8 E# h" _0 m% h* R) J
- o* {5 N8 G( h. S/ h
区块头就是以太坊中的区块链部分。它保存了前一个区块(也可称为父区块)的哈希值,通过区块头的连接形成了一条由密码学背书的链。
8 v9 b& `; _+ _. b$ n' j' P: G( b$ X8 X
区块体包含了此区块中记录的一系列交易,以及叔块(ommer)区块头列表。如果想要进一步了解叔块,我推荐阅读这篇文章。
$ E* w5 _9 z8 @
7 g5 S7 f4 |! J( |* I( M-以太坊区块的抽象示意图-9 x( E! [) I- H) o
# A# U7 h) R/ j! a, d3 H
下面就来介绍区块头包括哪些部分。
3 U' }; u# N! o2 p. u
: x9 [% [9 N( E) ~parentHash: b, d% C4 C9 o  ]) x

+ O. H0 }* @$ o前一个区块的区块头哈希值。每个区块都包含前序区块的哈希值,一路可回溯至链上的创世块。这也就是维护数据不会被篡改的结构设计(任何对前序区块的篡改都会影响后续所有区块的哈希值)。" q. E5 b$ o2 w8 {. t. }" G

8 Z/ Q. _! b/ f8 FommersHash% K2 f$ c0 A! j0 n: U) R$ J, u( L

! `1 b' Z0 y" k. r1 @* d5 U9 `  v叔块头以及部分区块体的哈希值。
6 O+ I) t# G. z
$ Z- n4 r) b) o) }$ w' Obeneficiary7 O; G3 Y/ |; a* N& J/ }! C

$ c8 g( @5 G- `3 l因为挖到此区块而获得收益的以太坊账户。3 e; c5 z# [! M) J: M- O

. \+ I: h% c( j0 L, xstateRoot
* v% L, V7 P; s& r0 L
" S- X- q) U) a  |) `世界状态树的根节点哈希值(在所有交易被执行后)。
8 {4 x1 `! g. ?: E
5 N% @! a* n. F$ b; Q3 o+ ntransactionsRoot
+ F' S+ R6 L; M1 ~
1 Y+ _/ }" ]. ^! z  G9 W4 p交易树根节点的哈希值。这棵树包含了区块体的所有交易。4 T' ~6 x3 j' c3 F  I7 |5 s

% p% v9 ?. K% u2 q: ^4 z. t% j& YreceiptsRoot4 D9 q, A5 M/ D4 o: C! W8 X# [

& Y8 J. l% c6 q每当交易执行时,以太坊都会生成对应结果的交易收据。此处就是这个交易收据树的根节点哈希。
: X# C& u3 |" J2 w% T$ e  U( ~) w; |0 A* n- |: Y
logsBloom# M: `; Y# x! m' V
0 T, A9 U' b9 b" A$ P& v7 G
布隆过滤器,用于判断某区块的交易是否产生了某日志(如果对这方面感兴趣,可以查阅 Stack Overflow 的这个答案)。这避免了在区块中存储日志信息(节省了大量空间)。. X+ ^9 q- E7 A4 z! |, F, y
; Y3 A, b5 b; A% ?2 `2 P6 y1 p
difficulty
- R2 P3 j0 w% s4 |8 k0 s$ x- [! ^+ o; Q% s+ z& B. U0 @
此区块的难度值。这是当前区块挖矿难度的度量值(此处不对此概念的细节和计算作介绍)。4 }  k. b( X0 w- G! l" Z* G  h+ d

% H9 T' x5 h) u  G6 M" C2 \number4 J8 O# C; D3 `- z' G

2 A% g9 S' [7 w% e( @2 g前序区块的总数。这标示了区块链的高度(即区块链上有多少区块)。创世区块的 number 为 0 。
0 J: n$ v' @0 J; }4 T" |/ O9 N
. }  H' l0 p# @7 d- {; jgasLimit: D( M/ j. e$ r5 h

1 F! B- Q' a. a; m0 u3 F$ J: R& w每一个交易都需要消耗 gas 。gas limit 标示了该区块所记录的所有交易可以使用的 gas 总量。这是限制区块内交易数量的一种手段。
: _( l$ t9 u$ H* `" y9 L$ o: w3 [) U4 P9 v/ D
gasUsed; x2 s) S+ Q' p% s, a& ^

. Z6 t+ U. |. [1 y9 H' P' Z区块中各条交易所实际消耗的 gas 总量。. L4 r9 G5 D! s- o0 m! |1 J

# \, r# W. p& M" J6 |) Gtimestamp
- V9 O9 P2 ]9 x' F9 O6 a) g6 T
; [4 t" e* v: R+ j区块创建时的 Unix 时间戳。谨记由于以太坊网络去中心化的特性,我们不能信任这个值,特别是撰写智能合约、涉及到时间相关的商业逻辑时不能依靠这个值。! v2 C1 s! w& y; T0 n5 Z, J  \

1 S3 S' n; X7 O: n6 b' v- s" j# wextraData. E( J! A3 j/ v* g  p9 ~" {# x5 P

. P% X4 a7 n+ s* c能输入任何东西的不定长字节数组。当矿工创建区块时,可以在这个区域添加任何东西。
0 C6 R9 L) O0 ~; T( C$ ~3 s/ V) w
5 v1 {7 Z4 }& _3 dmixHash2 o$ ^1 c( i. @

+ A9 G  L* K4 e! X/ ~- y; ?用于验证一个区块是否被真正记录到链上的哈希值(如果想要真正理解这个概念,建议阅读这篇文章 Ethash proof-of-work function )。
$ [' G' r2 ^+ J( m  Y  l: L% V, X- G+ m* ]. d
nonce& [: z8 l$ x* q; D# V6 Y

# _# {6 ?& T; ~! m! W4 n和 mixHash 一样,用于验证区块是否被真正记录到链上的值。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

olwww 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1