以太坊黄皮书连载(二)

天露   |     |   725 次阅读

翻译作者:Jorden Gao 邮箱:gaotl33@126.com / tianlu.jorden.gao@gmail.com
微信账号:wa713714
本文作者:Dr. Gavin Wood,以太坊&Ethcore的创始者 邮箱:GAVIN@ETHCORE.IO

公式解释说明:由于网页不默认word公式的格式,以下为公式的解释说明:
1.B_20中为下角标;
2. f
^* ((x_0,x_1,…))≡( f_ (x_0),f_ ^ (x_1),…) 中^为上角标;
3. R_u∈P ∩〖 R〗b∈B_256 中〖 〗忽略不计;
4. D(H)≡ {(D_0^ if H_i^( )=0
{ max⁡〖(D_0^ ,P(H)
(H_d^ )^ +x*ε1+ϵ) if H_i^( )<〗 N_H^( )
{max⁡(D_0^ ,P(H)_(H_d^ )^ +x*ε2+ϵ) otherwise)

中3 { 是一个大个{
若有公式疑问,建议下载原文对应公式看;再次抱歉!

4. 区块,状态和交易

已经介绍了以太坊的基本概念,我们将更详细地讨论一个交易、区块和状态的含义。
4.1全局状态。全局状态是一种映射在地址(160位的识别符)和账号之间的状态(一种RLP连续的数据结构,见附件B)。虽然它没有储存在区块链上,但是它被认为它的功劳是全力支撑映射在一个修改过的梅克尔帕特里夏树中(“Modified Merkle Patricia Tree”- 缩写为trie,见附件D)。Tire 需要简单的数据库后端去支持字节数组到字节数组的映射;我们命名这底下的数据库为状态数据库。它有一系列的好处;第一这个结构的根节点是加密的且依赖于内部的数据,同样地它的哈希在整个系统中能被作为一个安全的身份。第二,作为一个不变的数据结构,因此它允许任何一个之前状态(根部哈希已知的条件下)去被召回通过简单地改变根部哈希值。因为我们储存了所以这样的根部哈希值在区块链中,我们能过简单地调回以前的状态。
这个账号状态包含以下四个区域:
随机数(“nonce”):在账号与相关的代码的这种情况下,一个标量值等于这个地址发送的交易数或者,由这个账号产生的合约创造的数量。在状态σ中对于地址a的账号,可以被表示成σ[a]n。
平衡(“balance”):一个标量值等于这个账号拥有的位(“Wei”)数。正式表示为σ[a]b。
根储存(“storageRoot”):一个编译在这个账号的储存内容中的(一个包含256位整数值的数组)梅克尔帕特里夏树根节点的256位哈希值编译进了trie,作为一个数组从256位整数钥匙的Keccak 256位哈希值到RLP编译的256位整数值。这个哈希值被表示为σ[a]s。
代码哈希值(“codeHash”):这个账号在EVM代码下的哈希值 – 这个代码就是当执行时需要这个地址去接受一个信息调用(“message call”);它是不可变的,不像在其他的领域一样,因此运行它之后就不能被改变。所有像这样的代码碎片是被包含在它们最近接受回应哈希值的状态数据库下。这个哈希值被正式的表示为σ[a]c,如果这个代码可能表示为b,则给定KEC(b)=σ[a]c。
因为我经常希望不是去暗指这trie的根哈希值而是去底层存储的钥匙或者值的集合,我定义一个方便的方程式:
(6) TRIE(LI^* (σ[a]s )) ≡ σ[a]s
在trie中这个函数的LI^是一对钥匙或者值集合,而且被定义成基于功能LI的元素扩展转换,定义为:
(7) LI ((k,v) )≡(KEC(k),RLP(v))
其中:
(8) k∈B32 ∩ v∈P

它应该被理解成σ[a]s不是这个账号的“本身的”成员而且也不能促成它的系列化。
如果代码哈希值区域是Keccak-256的空集合的哈希值,例如: σ[a]c=KEC(()),那么这个代码值表示为一个简单的账号,有些时候简称为一个“非合约”账号。
因此我们可能定义一个世界状态的子函数Ls:
(9) LS (σ)≡{p(a):σ[a]≠0}
其中:
(10) p(a)≡(KEC(a),RLP((σ[a]n,σ[a]_b,σ[a]_s,σ[a]_c ) ))
这个函数,L_S,是被跟随使用在trie函数后,为了提供一个世界状态的简介身份(哈希值)。我们认为:
(11) ∀a:σ[a]=∅∪(a∈ B
20 ∩ v∈(σ[a]))
其中v是一个这个账号的有效性功能:
(12) v(x)≡x_n∈P_256 ∩ x_b∈P_256 ∩x_s∈B_32 ∩ x_c∈B_32
*
4.2.家园(“Homestead”)。一个兼容公共网络的显著区块数字是一个交易数标记在以太坊平台的前沿(“Frontier”)和家园(“Homestead”)阶段,我们用符号表示为N_H,因此定义:
(13) N_H≡1,150,000
这个协议过去在这个区块中被升级,因此这个符号在某些方程中出现不同的账号。
**4.3.交易。
交易(符号,T)是一个单一密码署名签名的指令,通过一个永久在以太坊中的操作者创建。当这个永久的操作者含有人类的性质成为假设,软件工具将被用在它的结构和传播 ^1。这里有两种类型的交易:一种是结果在信息调用中、一种是结果在相关的代码(众所周知为“合约创建”)下的新账号创建。两种类型都为公用领域的一个数字。

(^1显著地,这样的“工具”最终将会变成那么有原因的迁移从他们基于人类的创造 – 或者人类可能变成有原因的中立 – 这里将会出现一个点当他们正确的被考虑为自治的代理人。例如:合约可能提供好处给人类去发送交易而且去开始他们的行动。)

随机数(“nonce”):一个标量值等于被发送者发送的交易数;表示为T_n。
燃料价(“gasPrice”):一个标量值等于被支付执行这个交易所有计算而产生的每个单位燃料的“位”数;表示为T_p。
燃料限制(“gasLimit”):一个标量值等于燃料被用于执行这个交易的最大限度值。它是被预先支付的,在任意计算完成之前和以后不会增加;表示为T_g。
接受者(“to”):一个信息调用的160-位地址的接受者,或者是给合约创建交易,∅,在这用去指示B_0这个数字;表示为T_t。
价值(“value”):一个标量值等于被转移到信息调用的接受者,或者合约创建,作为一个新建账号的天赋;表示为T_v。
v, r, s:交易签名和用去决定交易的发送者的对应值;表示为T_w,T_r 和T_s。详细见附件F。

另外,一个合约创建交易包含:
初始化(“init”):在EVM-代码中为了账号初始化的过程而指定的一个没有限制大小的字节数组,表示为T_i。
初始化是EVM-代码的碎片;它返回主干,每次执行这个账号的代码第二个碎片都会收到一个消息调用(无论是通过交易还是因为内部执行代码)。初始化仅仅被执行一次在账号创建和之后立即丢弃的时候。
相对之下,一个信息调回交易包含:
数据(“data”):在信息调用输入数据中指定的一个没有限制大小的字节数组,表示为T_d。
附件F详细描述了这个函数,S,它传输交易给发送者,和画出SECP-256k1的ECDSA曲线,利用这个交易的哈希值(除了最后三个签名的区域)作为一个数据去签名。暂时我们只是简单地声称这个给定交易的发送者T能被看成S(T)。
(14) LT (T) ≡ { (Tn,Tp,Tg,Tt,Tv,Ti,Tw,Tr,Ts) if Tt=∅
{ (Tn,Tp,Tg,Tt,Tv,Td,Tw,Tr,Ts) otherwise
在这里,我们认为所有的成分是被RLP作为一个整数值代替,除了特有长度字节数组的T_i和T_d。
Tn∈P_256∩T_v∈P_256∩ T_p∈P_256∩
(15) Tg∈P_256∩T_w∈P_5 ∩ T_r∈P_256∩
T_s∈P_256∩〖 T〗d∈B ∩〖 T〗i∈B)
其中,
(16) P_n ={P:P∈P∩P<2^n} P为元素,属于P为集合
这个地址的哈希值T_t稍微有点不同:它是一个20字节的地址哈希值,或者成为一个创建合约交易(因此表示为∅),它是RLP空字节系列,因此表示为数字B
0:
(17) T_t∈{(B
20 if T_t≠∅
{ B_0 otherwise
4.4.区块。在以太坊中区块是相关信息块的收集(区块头),H,响应的信息聚集一起构造交易,T,和其他区块头数据的集合U,它众所周知有一个父块,等于这个父区块的父块的父块(这个的区块为ommers ^2)。这个区块头包含一些信息的碎片:

( ^2ommer是 最流行(但是提起的不多)的性别中立项目,表示为“父母的兄弟”;见http://nonbinary.org/wiki/Gender_neutral_language#Family_Terms

父块哈希值(“parentHash”):在整体中说,父块的区块头Keccak256位哈希值,表示为H_p。
ommers哈希值(“ommersHash”):区块中ommers列表部分Keccak256位哈希值,表示为H_o。
受惠者(“beneficiary”):从迁移区块的成功采矿中所有费用收集起来的160位地址。
状态根(“stateRoot”):trie状态根节点的Keccak256位哈希值,在所有交易被执行和定稿被应用;表示为H_r。
交易根(“transactionsRoot”):trie结构根节点的Keccak256位哈希值移植到这个区块交易列表中的每个交易;表示为H_t。
接收人根(“receiptsRoot”):trie结构根节点的Keccak256位哈希值移植到这个区块交易列表中的每个交易的接收人;表示为H_r。
日记块(“logsBloom”):日记块写下含有可索引的信息(写日记人地址和日记主题),这信息包含每个日记里交易列表中每个交易的接收人的登录信息;表示为H_b。
难度(“difficulty”):一个响应的标量值为了表示这个区块的难度等级系数。这个等级系数能从之前区块难度等级系数和时间戳中被计算出来;表示为H_d。
区块数字(“number”):一个标量值等于产生区块的数字。创世块是数字0;表示为H_n。
燃料限制(“gasLimit”):一个标量值等于每个区块当前燃料开支的限制值;表示为H_l。
燃料使用(“gasUsed”):一个标量值等于当前区块中交易所用的所有燃料;表示为H_g。
时间戳(“timestamp”):一个标量值等于当前区块产生时的合理Unix时间输出;表示为H_s。
额外数据(“extraData”):包含这个区块的任意字节相关数据。必须是少于等于32为;表示为H_x。
混合哈希值(“mixHash”):一个与随机数一起证明已经在这个区块中完成的充分的计算力总量的256位哈希值;表示为H_m。
随机数(“nonce”):一个与混合哈希值一起证明已经在这个区块中完成的充分的计算力总量的256位哈希值;表示为H_n。

剩下的区块成分是ommer区块头中的一个列表(与上面数据格式一样)和一系列的交易。我们用一个区块B去表示为:
(18) B≡(B_H,B_T,B_U)

4.4.1.交易收据(“transReceipt”)。为了去编译信息关于每一个有关系的交易而且可能是一个有用的工具去形成一个零知识证明(“zero-knowledge proof”),或者索引和搜索。我们编译每一个包含当前交易执行的某些信息为交易收据。每个收据(在第i个交易中表示为B_R [i])是被放置于一个带关键字索引的trie中和这个区块头中被记录下的根值,表示为H_e。
交易收据是一个包含四个项目的数组:交易后的状态R_σ;当前区块中交易发生后收据中立即保存积累性燃料使用值R_u;交易执行中创建的日记集合R_l;和日记块过滤器中包含这些日记的信息R_b:
(19) R≡(R_σ,R_u,R_b,R_l)
函数L_R是筹备从一个交易收据转变为一个系列化的RLP字节的数组:
(20) L_R (R)≡(〖TRIE(L_S (R〗σ)),R_u,R_b,R_l)
因此这个交易后的主状态,R
σ是被编译在trie结构中,根值是trie格式中的第一个值。
我们声称R_u,积累性的燃料使用值是一个正整数和日记块过滤器,R_b,是一个大小为2048位的哈希值(256字节):
(21) R_u∈P ∩〖 R〗b∈B_256 中
这个日记写入,R_l,是一系列日记写入,例如被称为:(O_0,O_1,…)。 一个日记写入O包含:O_a,是一个写日记人地址的数据,O_t,是32位日记主题的集合和O_d,是一些数据字节的数字:
(22) O≡(O_a,(O_t,O_t1,…〖),O〗d)
(23) O
a∈B_20∩ ∀
(t∈O_t ) ∶ t∈B_32 〖∩ O〗d∈B
我们定义这个日记过滤器的功能,M,去减少在单个256字节哈希值中的一个日记写入:
(24) M(O)≡⋁(t∈{〖 O〗_a∪〖 O〗_t})▒ (〖 M〗(3:2048) (t))
其中〖 M〗(3:2048)是一个特别的日记过滤器,它的集合是第3位到2048,给定的一个任意的字节序列。它是通过这个字节序列Keccak-256哈希值中的每第一个三对字节的低顺序的前11位。表示为:
(25) 〖 M〗
(3:2048) (x:x∈B)≡ y:y∈B_256 其中:
(26) y≡ (0,0,…,0) 除:
(27) ∀(i ∈{0,2,4}) :B(m(x,i)) (y)=1
(28) m(x,i)≡ KEC(x)[i,i+1] mod2048
其中B是位参考函数,例如:B_j (x)等于字节数组中的x索引j位(从0开始编入索引)。
4.4.2. 历史的有效性(“Holistic Validity”)。如果搞一个区块满足以下几个条件,我们能声称这个区块是有效的:它必须与ommer保持内部一致,而且交易区块哈希值和给定的交易B_T(详细描述在第11节),当按基本状态σ(起源于父块中最后的状态)顺序执行,就会产生一个新的身份状态H_r:
(29)

H_r≡ TRIE(L_S (Π(σ,B))) ∩
H_o≡ KEC(RLP(L_H^* (B_U ))) ∩
H_t≡ TRIE({∀i<|(|B_T | )|,i∈P:p(i,L_T (B_T [i]) )}) ∩
H_e≡ TRIE({∀i<|(|B_R | )|,i∈P:p(i,L_R (B_R [i]) )}) ∩
H
b≡⋁
(r∈B_R)▒ (r_b)

其中p(k,v)仅仅是与RLP互相转化。既然这样,k为这个区块中的交易索引和v为交易收据:
(30) p(k,v) ≡ (RLP(k) , RLP(v))
此外:
(31) TRIE(L_S (σ))=〖P(B_H)〗(H_r )
因此TRIE(L_S (σ))是包含状态σ和RLP编译值的一对钥匙值的梅克尔帕特里夏树的根节点哈希值,〖P(B_H)〗
直接定义为区块B 的父块。
这些值由交易的计算产生,特别是交易收据B_R,这个通过交易状态累积函数Π定义,在11.4小结详细地用公式表示。
4.4.3. 串行化(“serialisation”)。函数L_B和L_H分别是区块和区块头的准备函数。更像这个交易收据准备函数L_R,当RLP转换被允许时我们声称这个结构的类型和顺序为:
(32) L_H (H)≡(H_P,H_o,H_c,H_r,H_t,H_e,H_b,H_d,H_i,H_l,H_g,H_s,H_x,H_m,H_n)
(33) L_B (B)≡( L_H (B_H),L_T^* (B_T),L_H^* (B_U))
随着L_T^和L_H^成为宽元素序列转换,因此:
(34) f_ ^* ((x_0,x_1,…))≡( f_ (x_0),f_ ^ (x_1),…) 其中f可为任何函数
因此这些成分类型被定义为:
(35) H_p∈B_32 ∩ H_o∈B_32 ∩ H_c∈B_(20 ) ∩
〖 H〗r∈B_32 ∩ H_t ∈B_32 ∩ 〖 H〗e∈B_32 ∩
H_b∈B_256∩〖 H〗_d∈P ∩〖 H〗_i ∈P ∩
H_l∈P ∩ H_g∈P ∩ H_s∈P_256 ∩
H_x∈B ∩〖 H〗_m∈B_32∩〖 H〗_n∈B_8

其中
(36) B_n≡ {B:B∈B∩|(|B| )|=n})
我们现在知道有一个严格的正式的区块结构的框架说明书。这RLP函数(见附件B)提供了一个标准的方法通过线或者本地的存储空间去转变这种结构成为一个字节的序列。
4.4.4. 区块头的有效性(“Block Header Validity”)。我们定义P(B
H)为区块B的父块,表示为:
(37) P(H)≡ B
H^∶KEC(RLP(B_H^')=B_P^
区块数字是这个父块数字加1:
(38) H_i^ ≡ P〖(H)〗(H_i^ )^ +1
一个标准的区块头H的难度被定义为D(H):
(39)
D(H)≡{(D_0^ if H_i^( )=0
{ max⁡〖(D
0^ ,P(H)(H_d^ )^ +x*ε1+ϵ) if H_i^( )<〗 N_H^( )
{max⁡(D_0^ ,P(H)
(H_d^ )^ +x*ε2+ϵ) otherwise)

其中:
(40) D_0^ ≡131072

(41) x≡ (P(H)_(H_d^ )^ )/2048

(42) ε1≡ {1 if H_s^ <P(H)_(H_s^ )^ +13
{-1 otherwise)┤

(43) ε2≡max⁡(1-[(H_s^ -P(H)(H_s^ )^ )/10],99)
(44) ϵ≡[2
^([(H_i^ )/100000]-2)]
一个标准的区块头H的燃料限制为H_l,它必须满足这个关系:
(45) H_l

(46) H_l>P(H)(H_l^ )^ -[(P(H)(H_l^ )^ )/1024] ∩
(47) H_l≥125000

H_s是区块H的时间戳,它必须满足这个关系:
(48) H_S>P(H)(H_S^ )^
这个机制执行了区块间时间的体内平衡;在最后两个区块间的一个更小的周期会导致难度系数的增加,因此额外的计算需求,保持喜爱一个周期的长度。相对下,如果这个周期过长,难度系数和下一个区块的预期时间也会被减少。
这个随机数,H_n必须满足这个关系:
(49) n≤ 2^256/H_d ∩m= H_m

有(n,m) = PoW (H_n,H_n,d)。
其中,H_n是这个新区块的区块头,但是里面不存在随机数和混合哈希值得成分,d是最近的DAG,一个大数据集合需要去计算这个哈希值。PoW是工作证明函数(见11.5小结):这个函数评估第一个项目成为混合哈希值的数组,也同时证明一个DAG是不是被正确地使用;这个函数使用第二个项目中的H和d评估是否成为一个假冒随机的密码学数字。给定一个大致统一的分配范围[0, 2^64),用这个期待的时间去寻找一个方法是和寻找难度系数H_d一样。
这就是区块链安全性的基础,同时也是为什么一个怀有恶意节点不能繁殖到最新创建的区块中而重写历史的重要原因。因为这个随机数必须满足这个要求,和因为它的满足取决于这个区块的内容和它依次地交易的组成、新的创建、有效性、区块的难度性、超出的时间、和挖矿可信节点部分大致需要的总算力。
因此我们能够定义这个区块头的有效性函数V(H)为:
(50) V(H)≡2^256/H
d ∩m= H_m ∩

(51) 〖 H〗d=D(H) ∩
(52) H_g≤H_l ∩
(53) H_l>P(H)
(H_l^ )^ +[(P(H)(H_l^ )^ )/1024] ∩

(54) H_l>P(H)
(H_l^ )^ -[(P(H)(H_l^ )^ )/1024] ∩
(55) H_l≥125000 ∩
(56) H_S>P(H)
(H_S^ )^ ∩
(57) H_i^ = P〖(H)〗(H_i^ )^ +1 ∩
(58) |(|H_x^ | )|≤32
其中(n,m) = PoW (H
n,H_n,d)。
另外说一句,额外数据(“extraData”)必须最大字节位数为32。
 
1 人喜欢