网赚论坛
标题:
以太坊紫皮书(中文版)
[打印本页]
作者:
drl01349nbj
时间:
2017-10-21 18:18
标题:
以太坊紫皮书(中文版)
以太坊紫皮书(中文版)
作者:Vitalik Buterin
译者&来源:LinktimeTech 微信公众号
在刚刚闭幕的以太坊Devcon 2大会上,以太坊创始人Vitalik分享了他的最新研究成果《以太坊紫皮书》,在此我们将其翻译成中文,供大家阅读。《紫皮书英文》原版大家也可以从我们的公众号中找到并阅读。当然,如此前沿和复杂的论文翻译是很大的考验,如果大家觉得以下内容有问题,请及时与我们反馈,我们将在后期的公众号文章中进行纠正。论文全文内容如下:
(为什么叫紫皮书?)
前言
在过去十年中,诸如Bitcoin、Namecoin和以太坊这些项目充分展现了密码经济共识网络对促成下一代去中心化系统的强大推力,并潜移默化的将开发视野从简单的数据存储和信息服务扩展到任何状态应用的后台管理。基于这个系统,在全球范围内提议和执行的应用,涵盖了全球低价支付系统,金融合同,市场预测,身份注册和现实世界产权,建立更安全的证书管理系统,甚至通过供应链对制造品进行溯源和跟踪管理。
但是,这个系统的技术基础仍然存在严重的效率问题。因为在网络上每个全节点都必须维护整个系统的状态和处理每个交易,整个区块网络效率受限于单个计算节点。现在大部分系统所采用的共识机制,工作量证明(POW),需要消耗大量的电力去运营; 基于POW机制的最大的工作区块链Bitcoin,消耗了相当于整个爱尔兰的用电量。
这篇文章为上述问题提供将POS和基于分片证明进行合并的解决方案。POS本身并不是一个新奇的主意,2011年就已经存在,但新的算法展现了实质性的好处,不仅解决了前一系统的缺陷,甚至拥有POW不曾有的属性。
POS可以被想象成一种虚拟挖矿。然而在POW模式下,用户需要花费一定的金钱买一台电脑,然后消耗真实的电力,其随机获得区块链的成本与消耗的电力大致成比例。在POS模式下,用户花费金钱购买系统内的虚拟代币,然后用一个内部协议机制将虚拟代币转换成虚拟电脑,系统模拟随机产生的区块的成本与购买成本大致成比例,达到了POW同样的出块效果,却不用消耗电力。
分片也并不新颖,在现行的分布式数据库设计中有超过10年的应用,但是到目前为止,研究将其应用在区块链上,仍有颇多限制。基本的路径是解决可扩展的挑战, 通过架构中的全球验证程序集合中的节点(在我们的情况下,通过股权结合证明了)被随机分配到特定的“碎片”,其中每个碎片并行处理全局状态的不同部分,从而确保工作是跨节点分布处理,而不是每个节点都重复做。
我们渴望实现以下目标
通过POS提升效率:共识机制不应该由挖矿进行保证,从而大大减少电力浪费,并且可以满足大量和持续发行ETH的需要。
快速的出块时间:在不威胁安全的前提下,出块速度达到最大值。
经济一致:一旦区块被制作,经过一定时间和事件的处理,大部分的验证者将‘全提交’那个区块,意味着他们将损失全部的以太币保证金在没有包含这个区块的历史记录(想想1000万价值的以太币),这是非常需要的,因为意味着大部分的碰撞不能通过节点进行传递或者不用破坏掉以太币就可以51%攻击。默认的验证者战略是被设计成保守的他们愿意做出高价值的承诺,诚信的验证者的风险应该很低。
可扩展性:应该不需要跑所有节点就可以运行区块链,例如在这样的情况下,所有节点包括验证节点只保持一小部分区块的数据碎片,然后用轻客户端技术访问剩余部分的区块。采用方式下,相对单个节点处理能力,区块链可以达到更高的交易处理吞吐量,同时运行区块平台所需的只是大量的普通个人电脑,因此也可以保证去中心化。
跨碎片通信:构建这样一类应用并实现应用之间的互操作性在理论上是具有最大可行性的。该类应用的资源使用达到一个临界点以至超出单个节点的计算能力和带宽限制,并且分别存储在不同节点和处于不同状态。抵抗计算审查:该协议设计为可抵抗大部分的恶意验证节点跨越所有碎片而发起的联合攻击,使得无效交易不能被打包到区块并成为整个区块链的一部分。在某种程度上,可以通过以太坊1.0的停机问题存在,但是我们可以通过引入保证调度的概念和保证交叉碎片信息使这个机制更加强健。
我们从描述一个算法开始,该算法实现目标1和2, 然后在第二个算法实现了目标3, 然后在第三个算法中一定程度上实现目标4,5(作为一个限制条件,对一个节点的计算能力的平方大致成比例,如(4)和一个24小时的延迟跨碎片信息,有可能建立更快的消息作为一个层上通过双用途的存款,在例(5)。对目标(4)和(5)的更强级别的满意,(6)也一样,使得重新设计2.1和3.0。
常数
我们设置:
BLOCK_TIME: 4 seconds (aiming on the less ambitious side to reduce overhead,针对不太有野心的目标去减少开销)
SKIP_TIME: 8 seconds (aiming on the less ambitious side to reduce overhead针对不太有野心的目标去减少开销)
EPOCH_LENGTH: 10800 (ie. 12 hours under good circumstances,12小时的良好状态)
ASYNC_DELAY: 10800 (ie. 12 hours under good circumstances12小时的良好状态)
CASPER_ADDRESS: 255
WITHDRAWAL_DELAY: 10000000, ie. 4 months
GENESIS_TIME: some future timestamp marking the start of the blockchain, say 1500000000
REWARD_COEFFICIENT: 3 / 1000000000
MIN_DEPOSIT_SIZE: 32 ether
MAX_DEPOSIT_SIZE: 131072 ether
V_LOSS_MAXGROWTH_FACTOR: 32
FINALITY_REWARD_COEFFICIENT: 0.6 / 1000000000
FINALITY_REWARD_DECAY_FACTOR: 1000 (ie. 1.1 hours under good circumstances)
MIN_BET_COEFF: 0.25
NUM_SHARDS: 80VALIDATORS_PER_SHARD: 120
最小的POS
(注意,后续内容假设读者有对以太坊1.0的基本了解)
我们可以创建一个最小可行的PoS算法,没有诸如敲定确定、额外的抗审查以及分片等特性。在地址CASPER_ADDRESS存在一个合约,其主要功能是追踪验证者集合的变化。该合约没有特殊的特权,除了调用该合约是验证区块标头过程中的一部分,而且是包括在创世区块,而不是通过交易被动态添加的。验证者集合初始设置在创世区块中,并可以通过以下函数进行调整:
deposit(bytes validation_code, bytes32 randao, address withdrawal_address): 保证金(字节validation_code,bytes32 randao,地址withdrawal_address)
接受一定量的以太币作为保证金,发送者指定一段验证代码(本质为EVM字节码,代码主要功能是用作一种公钥,以便后续其他的节点验证由他们进行签名的区块数据以及相关的网络共识消息),一个随机提交的交易(一个32字节的哈希用于验证者的选择;详见下文)和最终提现地址一并发送。值得注意的是,提现可以在一个特定的地址发送,该地址的合约功能唯一用途就是特定的地址条件下释放资金,如果需要还可以双重用保证金。如果所有参数都被接受,在下一个时期将增加该验证者到验证者集合。(例如,如果保证金在第N个时期请求提取, 而验证者在第N+2个时期被加入验证者集合,这个一个时期等于EPOCH_LENGTH个区块时间周期)。验证代码的哈希值(叫做vchash)可以被验证者用作识别号;不同验证者具有同样的哈希值是被禁止的。)
startWithdrawal(bytes32 vchash, bytes sig):
开始撤回流程,要求一个签名,该签名需要通过验证者的验证代码。如果签名通过,从下一个时期开始,验证者被从验证者集撤回。注意,这个函数不退回以太币。
还有一个函数:
withdraw(bytes32 vchash):
撤回验证者的以太币到指定的提现地址,增加奖励减少惩罚,只要验证者已经从验证者活动集合中通过使用 StartWithdrawal至少是WITHDRAWAL_DELAY几秒前撤回。
准确的讲,验证代码就像是放入区块标头的哈希码,加上签名,如果签名有效返回1,反之,则返回0。这个机制确保了我们不会将验证者锁定到任何一个特殊签名的算法,相反允许验证者使用验证代码从多重私钥验证签名取代单一验证,也允许使用Lamport签名对抗量子计算机的攻击。这个代码在黑匣子环境下通过使用新的CALL_BLACKBOX操作码执行,以保证执行独立于外部状态。这样可以防止一些攻击,如一个验证者创建了验证代码在状态良好的时候返回1,在状况不好的时候(例如 Dunkle inclusion)返回0.
deposit函数中randao 参数的值应该是计算一段长链哈希值结果,即设置秘密随机的X,执行计算randao = sha3(sha3(sha3(sha3(.....(sha3(x))…))。每个验证者提供randao的值保存在Casper 合约中的存储空间。
Casper合约也含有一个叫GlobalRandao的变量,初始化为0。这个合约含有一个函数getValidator(uint256 skips):返回 skips 跳过以后的验证者的代码。例如 getValidator(0)返回第一个验证者(验证者一般来讲可以创造区块),getValidator(1)返回第二个验证者(如果第一个不能创建区块,验证者可以创建)
每个验证者都是通过伪随机算法从目前活动的验证者集合进行选择,随机对初始保证金规模进行加权,并以Casper 合约中的globalRandao值为伪随机种子。除了签名外,一个有效的区块也必须包含为那个验证者目前保存Randao的原像。这个原像然后替换保存Randao值,然后也通过异或运算保存到合约的globalRandao值中。这样,一个验证者生成的每一区块都要求脱掉一个验证者的randao的一层。这是一种基于在这里解释( http://vitalik.ca/files/randomness.html )的随机算法。
总之,一个区块必须包含的如下的额外数据:
其中,vchash是验证代码的32字节哈希值,用于快速识别验证者。randao含义如上所描述(也是32字节),sig是签名,可以是任意长度(虽然我们将区块标头的大小限制为2048字节)。
创建区块所需要的最短时间可以简单的定义为: GENESIS_TIME + BLOCK_TIME * + SKIP_TIME * 。
在实际过程中,这意味着,一旦发布了某个区块,那么下一个区块的0-skip验证者会在BLOCK_TIME秒之后发布,同理,1-skip验证者则在BLOCK_TIME + SKIP_TIME秒之后发布,以此类推。
如果一个验证者发布一个区块太早,其他的验证者会忽视该区块,直到在规定的时间之后,才会处理该区块(该中机制的进一步描述和验证详见这里(http://vitalik.ca/files/timing.html);短BLOCK_TIME和长SKIP_TIME之间的不对称性,可以确保:在正常情况下,区块的平均保留时间可以非常短,而在网络延迟更长的情况下,也可以保证网络的安全性)。
如果一个验证者创建了一个包括在链内的区块,他们得到的区块奖励相当于此周期内活动验证者集合内以太的总量乘以REWARD_COEFFICIENT * BLOCK_TIME。因此,如果验证者总是正确的履行职责,REWARD_COEFFICIENT本质上成为验证者的“预期每秒收益率”;乘以~3200万得到近似的年化收益率。如果一个验证者创建了一个不包括在链内的区块,之后,在将来的任意时间(直到验证者调用withdraw函数为止)该区块标头可以作为一个“dunkle”通过Casper合约的includeDunkle函数,被包括在链内;这使得验证者损失了相当于区块奖励的钱数(以及向包括dunkle在内的当事方提供一小部分罚款作为激励)。因此,验证者应当在确定该区块在链内的可能性超过50%,才实际创建该区块;该机制不鼓励所有链上的验证。验证者的累计保证金,包括奖励和罚款,存储在Casper合约的状态内。
“dunkle”机制的目的是为了解决权益证明中的“零赌注”的问题,其中,如果没有罚款,只有奖励,那么验证者将被物质激励,试图在每个可能的链上创建区块。在工作量证明场景下,创建区块需要成本,并且只有在“主链”上创建区块才有利可图。Dunkle机制试图复制工作量证明中的经济理论,针对创建非主链上区块进行人工罚款,来代替工作量证明中电费用的“自然罚款”。
假设一个固定大小的验证者集合,我们可以很容易的定义分叉选择规则:计算区块数,最长链胜出。假设验证者集合可以变大和缩小,但是,该规则就不太适用了,因为作为少数支持的分叉的速度一个时期以后将像多数支持的分叉一样。因此,我们可以用计算的区块数代替定义的分叉选择规则,给每个区块一个相当于区块奖励的权重。因为区块奖励与积极验证的以太总量成正比,这确保了更积极验证以太的链得分增长速度更快。
我们可以看出,这条规则可以用另一种方式很方便的理解:基于价值损失的分叉选择模型。该原则是:我们选择验证者赌最多价值的链,就是说,验证者承认除了上述的链外,所有其他链都会损失大量的资金。我们可以等同认为,这条链是验证者失去资金最少的链。在这样一个简单的模式中,很容易看出这如何简单的对应着区块权重为区块奖励的最长链。该算法是尽管简单,但用于股权证明的实现来说也足够高效。
添加敲定
下一步是增加经济敲定的概念。我们按照以下方式进行。在区块标头内部,除了指向上一个区块的哈希之外,现在验证者也对某个以前区块FINALIZATION_TARGET敲定概率做出了一个断言。该断言被当做一个赌注,如“我相信区块0x5e81d……将被敲定,并且在所有区块史中,如果这一断言是错误的,我愿意损失V_LOSS,假设在所有区块史中,这一断言是正确的,我将得到V_GAIN。”验证者选择odds参数,而V_LOSS和V_GAIN,按照如下方式计算(令total_validating_ether为活动验证者集合的以太总量,MAX_REWARD是允许的区块奖励的最大值,bet_coeff是下文定义的系数):
BASE_REWARD = FINALITY_REWARD_COEFFICIENT * BLOCK_TIME * total_validating_ether
V_LOSS = BASE_REWARD * odds * bet_coeff
V_GAIN = BASE_REWARD * log(odds) * bet_coeff
BASE_REWARD = FINALITY_REWARD_COEFFICIENT * BLOCK_TIME * total_validating_ether
V_LOSS = BASE_REWARD * odds * bet_coeffV_GAIN = BASE_REWARD * log(odds) * bet_coeff
V_GAIN and V_LOSS values relative to the BASE_REWARD, assuming bet_coeff = 1,假设bet_coeff = 1,V_GAIN值和V_LOSS值与BASE_REWARD的相关性
FINALIZATION_TARGET从null开始, 但是区块1期间,它被设置成区块0,。bet_coeff初始(开始)值被设置为1,另一个变量cached_bet_coeff设置为0。但是bet_coeff不能减少到低于MIN_BET_COEFF,在每个区块,我们设置bet_coeff -= bet_coeff / FINALITY_REWARD_DECAY_FACTOR,cached_bet_coeff -= cached_bet_coeff / FINALITY_REWARD_DECAY_FACTOR(这确保了总有激励驱动去打赌)。当创建一个区块,验证者得到BASE_REWARD * log(MAXODDS) * cached_bet_coeff,其中MAXODDS是最大的可能赔率,如MAX_DEPOSIT_SIZE / BASE_REWARD。该机制随所实现的是,一旦某一区块被确定被敲定,验证者从中得到奖励,就像他们以最大odds继续进行验证一样。这确保了,验证者不会受到不正当的激励而共谋通过延迟敲定某个区块以获得最大收益。
当Casper合约确定FINALIZATION_TARGET已被敲定(即已知区块的总价值损失超过某个阈值),我们将新的FINALIZATION_TARGET设置成当前区块,我们设置cached_bet_coeff += bet_coeff,并且bet_coeff重新设置为1。从下一个区块开始,敲定过程重新开始设置新的FINALIZATION_TARGET。如果,有一个短链分裂,敲定过程可能同时处理多个区块,甚至是不同高度的区块;但是,鉴于区块投注的默认验证者策略,以及支持它的最高价值损失,我们预计收敛过程倾向于选择他们其中的一个(此处的收敛参数基本上与最小权益证明相一致)。
当新的区块敲定过程开始启动时,我们期望最初的赔率很低,这表示验证者对短范围分叉的恐惧,但是随着时间的推移,验证者愿意投注的赔率会逐渐增加。特别的如果他们看到其他验证者对该区块进行高赔率投注,验证者的赌注也会增加。可以预计,该区块的价值损失将以指数倍增加,从而在对数时间内,达到最大“总保证金损失”。
在区块标头的额外数据中,我们现在将所需的数据格式更改为以下格式:
其中区块哈希是上个打赌的区块的哈希,并且logodds为1字节值,代表对数形式的赔率(即,0对应1,8对应2,16对应4等)。
请注意,我们不能允许验证者完全自由地设置赔率。考虑如下场景,如果有两个竞争关系的敲定目标,B1和B2(即存在两个链,其中一个的FINALIZATION_TARGET设置为B1,另一个的的FINALIZATION_TARGET设置为B2),并且围绕B1开始形成共识,然后一个恶意验证者可能会突然对B2投入一个高赔率赌注,它的价值损失足够影响共识,从而引发短范围分叉。因此,我们使用以下规则,通过限制V_LOSS来限制赔率:
令V_LOSS_EMA为一个指数移动平均线,设置如下。V_LOSS_EMA开始相当于区块奖励。对于每个区块周期,V_LOSS_EMA设置为V_LOSS_EMA * (V_LOSS_MAXGROWTH_FACTOR - 1 - SKIPS) / V_LOSS_MAXGROWTH_FACTOR + V_LOSS,其中SKIPS是跳过的数量,V_LOSS是该区块选择的V_LOSS。设置V_LOSS_MAX为V_LOSS_EMA * 1.5。限定V_LOSS的值为该值。
该规则设计上引入了一个安全约束:当至少(样本)三分之二的其它验证者风险为x后,当前验证者的风险仅可以为1.5x。这与拜占庭容错共识算法的事先承诺或承诺模式类似,一个验证者应等待其他三分之二的验证者完成给定的步骤后,才能进行下一步,并确保一定的安全,也确保大多数共谋不能参与“恶意破坏”攻击(如,让其他的验证者讲大量赌注添加在一个区块,并且随后推动共识到一个别的区块),无法共谋,因为共谋本身需要耗费大量资金(实际上,共谋损失金钱的速度比受害者损失金钱的速度更快,这是一个显著的特性,因为它确保,在大多数敌对情况下,恶意操作者会随着时间的推移,经常会被“淘汰”。)
如果一个区块作为一个dunkle被加入链中,赌注被处理,并且罚款和奖励也会产生。例如,如果有两个高度为5000的区块A1和A2,互为竞争的敲定目标,并且有两个高度为5050的区块B1和B2(两区块均以A1为上一代区块),并且验证者在B1上构建区块C,对A1下赌注,随后,如果B2最终确定为主链区块,B1和C将成为dunkle,并且C也将因B1 vs B2下错注而被惩罚,但是还是会因A1被赌对而进行奖励。
然而,假设C中的V_LOSS是这样的,如果B1包含在内,则V_LOSS < V_LOSS_MAX;如果B2包含在内,则V_LOSS > V_LOSS_MAX。之后,为了保证预期的价值损失特性,我们制定了一个额外的罚款:即使验证者赌对了,但我们仍以V_LOSS - V_LOSS_MAX对他们进行处罚。因此,我们有效地将V_LOSS赌注,分解成(i)价值损失V_LOSS_MAX的赌注和(ii)V_LOSS - V_LOSS_MAX的单纯价值销毁,从而保证这种规模过大的赌注仍仅通过V_LOSS_MAX经由分叉选择规则变换。这意味着投注在某种意义上是不“完全的”,因为如果该区块的子代区块中的很多都分叉了,即使该区块已经完成敲定确定,某个区块的赌注仍可能引起罚款。在投注模型中的单纯价值损失,被认为是对价值损失分叉选择规则利润纯度的一个可接受的权衡。
计分与策略实现
价值损失计分可以通过以下算法实现:
保持追踪最新的敲定的区块。如果有多个敲定的区块不兼容,返回一个大的红色的闪烁错误,因为这表明一个敲定的逆转事件发生了,并且客户端的用户可能需要使用额外的链源确定发生了什么。
保持追踪所有敲定的候选区块,即该区块的子代区块。对于每一个候选区块,保持追踪该候选区块的价值损失。
从最接近的敲定区块开始,保持追踪每个敲定候选区块的最长链及其长度。链的“总权重”是其敲定的候选区块祖先的价值损失加上链的长度乘以区块奖励。如果链中没有敲定的候选区块,那么就单独使用链的长度乘以区块奖励作为其总权重。“链头”是链中权重最大的最新区块。
此处用于举例的V_LOSS;在现实中,他们不会被允许这样快速的增长,并且B或C会要求A上的较高的V_LOSS成为敲定候选区块。
一个简单的验证者策略是仅在头部创建区块,并且做出敲定赌注,此处的价值损失是所描述的最大价值损失的80%。
轻客户端同步
敲定机制开启了一个快速轻客户端同步算法的大门。该算法包括以下几步:
令X是您已经确认的最新状态(初始为创世状态)。
在X时期或X时期后查询网络当前最新的敲定目标(谨记:当协议认为当前区块的前一区块被敲定时,此时的敲定目标为该区块。)。调用最新的敲定目标Fn和以前的敲定目标Fp。
查询网络Fn前的k个区块。这些区块将下注,筹码是它们在Fp上的整个以太币池子。
通过Merkle分支查询您已经敲定的状态,验证验证者创建的这些区块,验证其在验证者集合中的的存在性和位置,并且针对k个区块的中第一个区块的初始状态,验证他们选择的正确性。
设置X为Fp的后状态。重复上述步骤,直到得到最新的敲定区块。从最新的敲定区块开始,使用上文的正常策略寻找链头。
非常值得关注的是,通过步骤1到5可以用两个网络请求和几秒钟计算来验证全天的区块。
分片
现在,我们考虑从一个分片扩大到多个分片。我们构建的模型如下。取代已有的单条区块链,我们现在拥有被我们称为“分片”的多条相关联的区块链。NUM_SHARDS分片的编号为分片0至分片NUM_SHARDS ? 1,其中分片0简单的作为常规股权证明区块链进行,其确定性如上所述,但是分片1……NUM_SHARDS ? 1工作机制有所不同。在每个时期的开始,为每个分片随机挑选VALIDATORS_PER_SHARD个验证者,并且被分配为下一个时期的验证者(如,n+1时期的验证者在n时期时被指配)。当调用getValidator(skip)以确定这些分片内一个分片的验证者,仅仅随机从选取的验证者集合中选择一个验证者(平等地分配,因为在挑选的时候就已经对保证金大小进行加权)。分片1……NUM_SHARDS ? 1的确定性赌注并未在分片内做出,而是在分片0内做出。当赌注被做出,它就被存储,赌注仅在子代区块周期结束后,才被处理(如,n+1时期的区块确定断言,将在n+3区块周期开始时,在分片0内进行处理)。
如果已经为一个分片挑选了一个验证者,那么这个验证者将需要调用Casper合约的registerForShard(bytes32 vchash,uint256 shard,uint256 index,bytes32 randao)函数,其中vchash是验证者的验证代码哈希,shard是分片ID,index是一个数值且0
欢迎光临 网赚论坛 (http://www.caifuba.net/)
Powered by Discuz! X3.1