Lec 20 比特币
阅读资料
比特币:一种点对点电子现金系统。在存在拜占庭参与者的情况下能够达成共识。解决了一个看似显然不可能的问题,完全构建在一群不可信的参与者之上,你并不知道他们是谁,其中一些必定是恶意的,然而比特币的安全性足以支撑金融交易。主要的技术挑战:盗用他人的钱、双花(double spending)。
- 对比SUNDR,相同点有:1)使用签名操作的日志;2)对日志内容达成共识等同于对状态达成共识;3)分叉(fork)是主要危险;不同点:1)会自动处理分叉
- 对比PBFT和Raft:主要的不同点:1)系统是开放的/无许可的,没有专门指定的服务器。2)服务器数量未知(因此投票变得困难)。
这种共识机制新颖且有趣。 BTW, 比特币的成功是一个意外。
我们看交易的流程。首先定义几个符号表示,
pub(user1): 新拥有者的公钥。H(prev): 该币前一次交易记录的加密哈希值。sig(user2): 前一个拥有者的私钥对交易的签名。
然后看,交易示例,假设X之前已将一枚币支付给Y: T6: pub(X), ...T7: pub(Y), H(T6), sig(X)
Y 向 Z 购买一杯咖啡并用此币支付 Z向Y发送公钥。 Y创建一个新交易并签名。 T8: pub(Z), H(T7), sig(Y)
Y将交易记录发送给Z。 确实是 pub(Z) T7 存在,哈希正确 使用 T7 中的 pub(Y) 验证 T8 的 sig(Y) 有效 verify(T8, T8.sig(), T7.pub()) == ok
Z 将咖啡交给 Y。
比特币只记录交易,不记录币、账户或余额, Z 的"余额":指向 Z 且 Z 知道私钥的未花费交易,一个币的"身份"是其(哈希值代表的)最近一笔交易。
其他人能花某个币吗?
- 当前拥有者的私钥签署下一次交易,因此必须持有者的私钥。
- 风险:攻击者可能窃取Z的私钥(如通过PC、智能手机或在线交易所)。
- 实际中这是个严重问题,难以很好地解决。
什么是双花问题?
- Y创建两个交易,分别将币支付给Z和Q,但都指向相同的哈希(H(T7))。
- Y分别向Z和Q展示不同的交易,导致Z和Q分别给Y提供了服务。
- 双花是比特币解决的最根本问题。
怎么解决双花的问题?
Solution: 一个"公共账本"将能揭露 Y 的双花行为。 发布所有交易的日志,确保所有人看到相同的日志及顺序。确保无人能取消发布或修改日志条目。Z, Q 只相信日志中看到的交易。结果:Z会看到Y→Z在前,接受Y→Z;Q会看到Y→Z在前,拒绝Y→Q。
关键问题是如何创建这样的账本?
Solution: 比特币对等网络, 许多对等计算机参与协议,每台都有完整的区块链副本。区块和交易在整个网络中传播。任何人都可以运行比特币节点!但假设诚实节点远多于恶意节点。
比特币区块链, 区块链包含所有币的所有交易,以便显示双花。每个区块包含:
- 前一区块的哈希值。
- 奖励交易。
- 交易列表。
- “随机数”(nonce)。
- 当前时间(时间戳)。
新区块每10分钟生成,包含自上一区块以来的交易。收款方在看到交易进入区块链后相信该交易
谁创建每个新区块?
Solution: 通过"工作量证明"进行的"挖矿"。 要求:H(block) 有 N 个前导零,每个对等节点尝试随机 nonce 值直到满足条件。尝试一个 nonce 很快,但大多数 nonce 不会成功。一个 CPU 可能需要数月才能创建一个区块,但有成千上万的节点在同时工作,使得第一个找到者的预期时间约为 10 分钟(尽管方差很大);获胜者将新区块泛洪给所有对等节点。
区块链下,Y -> Z 交易如何工作?
Solution:
- 开始:所有节点都知道 ...<-B5, 并且正在挖掘区块 B6(尝试不同的 nonce)
- Y 向节点发送 Y->Z 交易,节点将其泛洪;
- 节点缓存该交易,直到 B6 被计算出来;
- 听到 Y->Z 的节点将其包含在下一个区块中
- 所以最终 ...<-B5<-B6<-B7,其中 B7 包含 Y->Z
B6 是否可能有两个不同的后继区块?
Solution: 是的。两个节点大约同时找到 nonce,或者网络延迟,第二个区块在第一个区块泛洪到所有节点之前被找到。两个同时产生的区块将是不同的,矿工知道略有差异的新交易集合,等等。如果出现两个后继者,区块链暂时分叉, 矿工在他们最先听到的区块上挖掘后继区块, 但如果听到更长的链,则切换到该链
Fork如何解决?
Solution:
- 每个节点最初相信它看到的第一个新的(且有效的)区块
- 尝试挖掘其后继区块
- 如果看到 Bx 的节点比看到 By 的多,则更多节点会为 Bx 挖矿,因此 Bx 的后继区块可能先被创建出来
- 即使正好一半对一半,一个分叉也可能先被延长,因为挖矿时间存在显著方差
- 节点一旦看到更长的分叉就切换到该分叉,因此更长的分叉获得更多挖矿算力来延长它, 所以对区块的共识倾向于得到加强
被抛弃分叉中的交易会怎样?大多数交易会同时存在于两个分叉中,但有些可能只存在于被抛弃的分叉中——出现后又消失!
如果 Y->Z 最终位于一个被抛弃的临时分叉中会怎样?
Solution: 这可能让Y实现双花,Z看到Y->Z; 然后它又消失了;接着Y可以广播Y->Q。因此,由于Fork,双花是可能的,但临时分叉极有可能被快速解决。如果 Z 看到 Y->Z 并且后面跟着几个区块,那么它被包含 Y->Q 的不同分叉超越的可能性非常小;如果 Z 销售高价值物品,Z 应等待几个区块确认后再发货; 如果 Z 销售廉价物品,或许只需等待一些节点看到并验证 Y->Z(甚至在 Y->Z 进入区块之前)即可
攻击者能否从一个旧区块启动分叉,用 Y->Q 代替 Y->Z?
Solution: 可以——但分叉必须更长,节点才会接受它;由于攻击者的分叉起点落后于主分叉,攻击者必须比所有其他节点的总和更快地挖出区块; 如果只有一个 CPU,即使创建几个区块也需要数月时间, 到那时主链已经长得多,没有节点会切换到攻击者较短的链
51% 攻击, 如果攻击者拥有超过50%的算力,则可能创建最长的链,导致双花。□
怎么理解工作量证明?
Solution:比特币的工作量证明(PoW)的一种思考方式是: 在节点中随机选择由谁来决定扩展哪个分叉,按 CPU 算力加权;如果大多数参与者是诚实的,他们将加强关于最长分叉的共识;随机选择意味着(小规模的)攻击者不会获得很多尝试将共识切换到不同分叉的机会。令人惊讶的是,在不知道参与者身份甚至数量的情况下,随机选择是可能的!
矿工的动机是什么?
Solution:关键是要有众多矿工,以使 51% 攻击更难。每个新区块支付给矿工一些新创造的比特币——作为奖励,区块包含获得新比特币的公钥,这是激励人们运行比特币节点的原因。难度(前导零的数量)自动调整,以使平均间隔为 10 分钟。后果,
可能凭空创造奖励货币吗?
Solution: 规则由(多数)节点中的代码决定,节点都运行着承认特殊奖励交易有效的代码。也就是说,多数节点说了算。
验证检查的步骤是?
Solution:
- 节点,新交易,前一笔交易存在,没有其他交易花费同一笔前一笔交易,签名由前一笔交易中公钥对应的私钥完成,然后将交易添加到待挖掘的下一个区块的交易列表中
- 节点,新区块: 哈希值有足够的前导零(即 nonce 正确,证明工作量),前一个区块哈希存在,区块中所有交易有效,如果新链比当前最长链更长,则节点切换到新链
- Z 客户端执行上述检查,或依赖某个节点执。
Y->Z在一个区块中,Z的公钥/地址在交易中,链中还有几个后续区块等等。□
常见问题
为什么采用开放 / "无需许可" / 去中心化的节点结构?
是否合理假设大多数节点是诚实的?
如果启动一个新的类似比特币的加密货币,只有少数节点,信任它是否合理?
比特币能良好扩展吗?
为什么比特币具有价值?
- 10 分钟 * 1 MB 区块 -> 约 5 笔交易/秒
- 信用卡系统处理约 5000 笔/秒
比特币是否可以扩展到大规模支付系统?
设计中的弱点
- 工作量证明消耗大量电力。
- 交易确认需要至少10分钟,高确认度可能需要60分钟。
- 网络泛洪限制了性能并可能成为攻击点。
- 最大区块大小和10分钟间隔限制了最大交易数。
- 对多数攻击易受影响。
- 匿名性不强,但吸引了非法活动。
- 用户保护私钥存在困难。
FQA
问:我不明白区块链为什么如此重要。每个交易都要求有所有者的签名难道不够防止比特币被盗吗?
答:签名并不够,因为它无法阻止所有者双重花费比特币,比如签署两笔交易,将同一比特币转给不同的接收者。区块链作为一种发布系统,确保一旦比特币被花费,许多参与者都会知道,从而能够拒绝第二次花费的尝试。
问:为什么比特币需要定义一种新的货币?使用现有货币(比如美元)不是更方便吗?
答:新货币(比特币)让系统可以通过新生成的货币激励矿工;使用美元会更难,因为普通人制造新的美元是非法的。此外,还需要一种方式将美元计价的区块链与外部的美元相连接。但你可以了解一下“稳定币”,例如 Tether。
问:什么是挖矿?
答:这是通过“工作量证明”找到新区块的过程,需要尝试许多不同的“随机数”(nonce)直到找到一个满足足够多前导零的区块哈希。
问:工作量证明的目的是什么?
答:它让攻击者很难让系统切换到一个恶意分叉的区块链上。可以将工作量证明视为在参与的 CPU 中随机选择谁有权决定扩展哪个分叉。如果攻击者只控制少数 CPU,则无法足够快地扩展新分叉,从而超越主区块链。
问:比特币是否可以使用比工作量证明更少资源消耗的东西?
答:工作量证明难以伪造或模拟,这对比特币这样完全开放的系统来说很有利,因系统中无法完全信任他人。主要替代方案是权益证明(PoS),以太坊、Algorand 和 Byzcoin 等使用了这种机制。对于参与者已知且基本可信的较小封闭系统,可以使用拜占庭协议,例如 Hyperledger,或其变种,如 Stellar。
问:爱丽丝能否通过分别向不同矿工子集发送“支付给鲍勃”和“支付给查理”的交易来双重花费同一个币?
答:假设爱丽丝确实这样做了。很可能其中一个子集的矿工会先找到新区块。假设第一个找到的区块是 B50,包含“支付给鲍勃”的交易,该区块将被广播给所有矿工。处理“支付给查理”交易的矿工将切换到 B50 的后续区块。这些矿工会验证交易,并注意到“支付给查理”中的币已在 B50 中花费,因此会忽略该交易。
博客阅读: Bitcoin协议如何工作
https://michaelnielsen.org/ddi/how-the-bitcoin-protocol-actually-works/
这篇文章清晰易懂的方式解释比特币协议背后的主要思想。从基本原理开始,逐步建立对该协议的运作方式,然后深入探究其本质,分析比特币交易中的原始数据。
比特币的基础竟然是密码学?比特币不是一种货币吗?怎么和加密扯上关系?事实上,比特币需要解决的问题——如何防止人们相互盗窃、冒充他人等。我们”重新发明“比特币,称为infocoin,这样可以让我们理解为什么这样设计,而不单单怎么做的。
第一阶段:一封带签名的意向书
那么,我们该如何设计一种数字货币呢?假设有一个人——我们叫她 Alice——她拥有一些数字货币,希望花掉它。如果 Alice 可以用一串比特代表她的钱,那我们如何阻止她多次使用同一串比特,从而“凭空印钞”?即便我们能解决这个问题,又如何阻止别人伪造这串比特,从而偷走 Alice 的钱?
这只是我们必须解决的众多问题中的两个,要让“信息变成金钱”,远比想象复杂。
第一版Infocoin:带签名的消息
假设 Alice 想给另一人 Bob 一个 infocoin。 她写下一条消息:“我,Alice,正在给 Bob 一个 infocoin。” 然后用她的私钥(private key)对这条消息进行数字签名,并将签过名的比特串广播给全世界。这当然算不上一个真正的数字货币系统,但它确实有一些优点:任何人(包括 Bob)都可以用 Alice 的公钥验证这条消息确实是 Alice 签的,别人无法伪造。 因此,Alice 无法事后否认自己发出了这条消息。 也就是说,这个协议能证明——Alice 确实有“把一个 infocoin 给 Bob”的意图。这两个特性——意图确立与有限防伪——确实是这个原型协议的亮点。严格来说,在这个协议中,“数字货币”指的就是那条签过名的消息本身: 即那串代表“我,Alice,正在给 Bob 一个 infocoin”的签名比特串。接下来的版本也类似——所有形式的数字货币都是越来越复杂的“消息”。
使用序列号让硬币唯一化。
第一个版本问题在于,Alice 可以反复把同一条签过名的消息发给 Bob。 假设 Bob 收到了十份“我,Alice,正在给 Bob 一个 infocoin”的签名消息。 这意味着什么?她是给了十个 infocoin?还是消息重复了?还是她在故意骗 Bob?显然,我们需要让每个 infocoin 唯一可区分,它们必须有一个序列号(serial number)。 于是,Alice 签署这样的消息:“我,Alice,正在给 Bob 一个 infocoin,序列号 8740348。” 下次她可以签署“我,Alice,正在给 Bob 一个 infocoin,序列号 8770431。” 这样,Bob(和其他人)就知道这是两枚不同的 infocoin。但要实现这一点,我们需要一个可信的序列号来源。 于是我们引入一个“银行”: 银行负责分配序列号、记录每个 infocoin 的所有者、验证交易是否合法。
具体来说:Alice 去银行说:“我想从账户里取出一个 infocoin。”,银行从她的账户扣除一个 infocoin,并为她分配一个从未使用过的序列号,比如 1234567。当 Alice 想把这个 infocoin 转给 Bob 时,她签署:“我,Alice,正在给 Bob 一个 infocoin,序列号 1234567",Bob 收到后不会直接接受,而是联系银行验证:(a) 这个 infocoin 确实属于 Alice;(b) Alice 没有花过这枚 infocoin。若验证通过,Bob 告诉银行他要接受这枚 infocoin,银行更新账本,标明这枚 infocoin(序列号 1234567)现在属于 Bob,不再属于 Alice。
让“每个人”共同成为银行
这个方案看起来不错,但我们可以做得更激进: 把银行去掉。去掉银行意味着整个货币系统再也没有单一中心机构。 而当你想到中央银行掌握的巨大权力——比如对货币发行量的控制——你会意识到这改变有多大。这个想法是:让所有人共同成为银行。 具体来说,假设所有使用 Infocoin 的人都维护一份完整的账本,记录每枚 infocoin 的归属。 这份共享账本就像是所有交易的公共记录。 我们称它为 区块链(block chain)——这正是 Bitcoin 中的称呼。
现在假设 Alice 想把一个 infocoin 转给 Bob。 她签署消息:“我,Alice,正在给 Bob 一个 infocoin,序列号 1234567。” Bob 收到后,用他自己的区块链副本检查该 infocoin 确实属于 Alice。 如果没问题,他就广播这条消息和他对交易的确认到整个网络,所有人更新各自的区块链。目前我们仍然有个问题:序列号从哪里来? 不过这其实不难解决,我们会在后面讲 Bitcoin 时处理。 现在更棘手的问题是:Alice 可能双花(double spend)。Alice 可以同时向两个人转账同一枚 infocoin:发给 Bob:“我,Alice,正在给 Bob 一个 infocoin,序列号 1234567”;发给 Charlie:“我,Alice,正在给 Charlie 一个 infocoin,序列号 1234567。” Bob 和 Charlie 都会查自己的区块链,发现 infocoin 属于 Alice,于是都认为交易合法,并广播确认。 这时,网络中的人该怎么更新账本? 即使大家最终一致,也必然意味着 Bob 或 Charlie 被欺骗了。表面上看,双花似乎不太容易成功——Alice 需要让 Bob 和 Charlie 几乎同时验证交易。 但现实中,她可以利用网络延迟或通信干扰让这种时间窗口更大。 这显然是危险的。
要防止双花,显然Bob不该独自验证交易。他应该把交易广播给整个网络,请其他人共同验证。如果全网大多数人同意交易合法,Bob 才能接受 infocoin,大家再更新区块链。这样,如果 Alice 试图一币两用,网络的其他成员会发现并通知 Bob 和 Charlie 拒绝交易。
不过,这个协议还存在许多模糊之处。 比如“足够多的人确认”到底是什么意思?我们不知道网络中有多少人,怎么定义“足够”?也不可能要求“所有人”确认。 这些问题我们暂时不解决。下一节我们会指出这种方案的严重缺陷,并在修复它的过程中,让这些模糊点变得更加精确。
工作量证明
假设 Alice 想在我刚才描述的基于网络的协议中进行双花。她可以通过接管 Infocoin 网络来实现这一点。设想她用自动化系统在 Infocoin 网络上创建了大量独立身份——比如说十亿个。和之前一样,她试图把同一个 infocoin 同时支付给 Bob 和 Charlie。但是当 Bob 和 Charlie 各自请求网络验证他们的交易时,Alice 的“马甲账号”淹没了整个网络——它们向 Bob 宣称“你的交易有效”,同时又告诉 Charlie“你的交易也有效”,从而可能欺骗其中一方甚至双方接受这笔交易。
为了避免这种情况,人们提出了一种巧妙的方法,称为工作量证明(proof-of-work, PoW),这个想法乍一看有些反直觉,它结合了两个关键点: 1. (人为地)让交易验证变得计算上昂贵;2. 奖励那些花计算资源来验证交易的人。这种设计让网络参与者仍然愿意帮助验证交易,即使这已变成一项计算密集型任务。其好处在于:交易验证的权重不再取决于一个人控制了多少个身份,而是取决于他能投入多少真实的计算能力。通过一些巧妙的机制设计,我们可以做到——想作弊的人必须拥有极其庞大的计算资源,使得作弊在现实中变得不可行。
工作量证明的基本流程:假设 Alice 向网络广播消息:“我,Alice,把编号为 1234567 的一个 infocoin 转给 Bob。”网络中的其他人听到这条消息后,会把它加入一个待验证交易队列中。比如,另一个用户 David 现在的交易队列可能是:
我,Tom,把编号 1201174 的 infocoin 转给 Sue。 我,Sydney,把编号 1295618 的 infocoin 转给 Cynthia。 我,Alice,把编号 1234567 的 infocoin 转给 Bob。
David 会检查自己本地保存的区块链(block chain),确认每笔交易都是合法的。他想帮助网络,把这些交易验证结果广播给其他人。但是,在他广播之前,协议要求他必须先解决一个困难的计算谜题——这就是工作量证明(Proof-of-Work)。 如果他没有找到这个谜题的解,其他节点不会接受他对交易的验证。
我们假设网络中约定了一个固定的哈希函数 h(例如比特币使用的 SHA-256)。 设 David 当前的交易队列为字符串 l,他需要找到一个数 x(称为 nonce),把它附加到 l 后面,然后计算h(l+x),例如 h("hello world!0") = 1312af178c253f84028d480a6adc1e25e81caa44c749ec81976192e2ec934c64,这显然不满足要求,1也不满足,不断尝试2,3,...最终在x=4250时,得到了h("Hello, world!4250") = 0000c3af42fc31103f1fdc0151fa747ff87349a4714df7cc52ea464e12dcd4e9,结果前面有4个零,成功通过了一个难度较低的工作量证明要求,若要求更高(比如前15位都是零),则需要更多计算。哈希函数的输出近似随机。 只要输入哪怕改动一个比特,输出就会完全不同,且不可预测。 所以如果我们要求哈希结果以 10 个零开头,那么平均需要尝试
假设 David 找到了合适的 nonce,他就可以广播新区块和这个解。其他人可以快速验证他的结果,然后更新自己的区块链。为了激励大家花算力参与验证,系统会给予奖励。 在 Infocoin 或 Bitcoin 中,这个奖励就是新发行的币。谁先验证成功,就能获得一定数量的 infocoin/bitcoin。
在比特币中,这个过程叫做挖矿(mining)。最初每个区块奖励 50 BTC; 每经过 210,000 个区块(大约四年),奖励减半。 目前(文中所述时)奖励为 25 BTC。 这个减半过程会持续到 2140 年,届时奖励将低于 $10^{-8} $BTC,也就是一个 satoshi(比特币的最小单位)。从那以后,比特币总量将不再增加。但挖矿者仍有激励,因为交易发起人可以附加交易费,由挖出该区块的矿工获得。 如今,交易费已经成为矿工收入的重要组成部分。
可以把 PoW 想成一场“算力竞赛”:每次参与验证都要花费一些计算资源。 一个矿工获胜(即挖出新区块)的概率,大致与他占整个网络算力的比例相同。 例如,若某矿工拥有全网 1% 的算力,他大约有 1% 的几率挖到下一个区块。因此,只要整个网络的总算力足够大,任何单个攻击者若想“篡改区块链”, 都必须掌握远超全网一半的计算资源,才有可能成功。 这使得双花攻击(double spending)在现实中几乎不可行。
为了让全网一致地认定交易的先后顺序(否则就无法确定谁拥有哪些 infocoin), 协议要求:每个新区块都要包含对前一个区块的指针。 这个指针其实就是前一区块的哈希值。 于是区块链的结构形成了一条链: 每个区块都连接到上一个区块,从而确立了交易的全序。

区块链中有时会出现分叉(fork),例如,当两个矿工几乎同时完成了区块的验证并将结果广播到网络时,有些节点可能先收到区块 A,有些则先收到区块 B。这样一来,部分节点更新了自己链上的区块 A,另一些则更新了区块 B,从而形成两条不同的链分支。这正是我们希望避免的问题:此时交易的先后顺序变得不明确,谁拥有哪些 infocoin 也可能暂时不清楚。 幸运的是,有一个非常简单的规则可以解决分叉问题。当出现分叉时,所有节点都会暂时保留两个分支的记录; 但矿工在挖矿时只会继续延长自己所看到的“最长链”。举个例子:假设出现了分叉,一部分矿工先收到了区块 A,另一部分先收到了区块 B。收到 A 的矿工会继续在 A 这条分支上挖矿,而另一部分则在 B 分支上挖。假设接下来在 B 分支上挖矿的矿工更快找到了下一个区块,那么整个网络很快就会倾向于接受 B 这条链,因为它更长。此时,A 上的未确认交易仍然在矿工的待处理队列中,因此不会丢失,最终会被重新打包并验证。反过来,如果 A 分支的矿工先延长了链,那么 B 分支的工作就会被迅速放弃,网络重新收敛为一条单一的线性链。

对于想要作弊的 Alice 来说,这种机制带来了巨大的困难。 一旦她所在的链比主链短,她必须追上或超过主链的长度,才能让她的版本被整个网络接受。 然而其他矿工不会帮助她,因为他们都在挖主链。 除非 Alice 拥有至少与全网其他矿工总和相当的算力(即超过 50% 的计算能力),否则她会越挖越落后。当然,她可能会偶然走运。 比如她只拥有全网 1% 的算力,但连续六次挖到了新区块,而其他矿工在这段时间里一个都没挖到。 这时,她可能一度超前,控制区块链。 但这种情况发生的概率仅为:
一些更深层次的问题。 工作量证明与挖矿机制引发了许多进一步的问题:
- 奖励多少才足以吸引人参与挖矿?
- infocoin 总量的变化如何影响整个经济体系?
- 挖矿最终会集中到少数人手中,还是保持分散? 如果集中化,会不会威胁系统安全?
- 当奖励趋于稳定时,交易费是否会成为主要激励? 这是否会让小额交易变得不划算?
无论最终哪条分支胜出,这一机制都确保区块链能够形成全网公认的时间顺序。在比特币系统中,一笔交易被视为“确认完成(confirmed)”需要满足两个条件:
- 该交易所在的区块位于当前最长链上;
- 在该区块之后又出现了至少 5 个新区块。
也就是说,这笔交易有 6 次确认(6 confirmations)。 这个过程为网络提供了充足的时间,来达成对区块顺序的一致认定。
Infocoin 协议也采用同样的策略。现在我们理解了时间排序,再回到双花攻击。 假设 Alice 想同时向 Bob 和 Charlie 支付同一个 infocoin。第一种方式:她试图在同一个区块中放入两笔相互矛盾的交易。 假设她掌握全网 1% 的算力,有时确实会碰巧挖到新区块并通过 PoW。 但这种双花交易会被网络中其他节点立即识别并拒绝,因此这种攻击无效。第二种方式:她向不同的矿工群体分别广播两笔交易, 让一部分矿工看到“付给 Bob”,另一部分看到“付给 Charlie”。 希望两笔交易都能被各自验证。然而,正如我们所见,网络最终只会确认其中一笔交易。 假设最终确认的是给 Bob 的交易,那么 Bob 就能放心收币; Charlie 看到自己的交易始终未被确认,自然会拒绝这笔交易。 所以这种方式也无法成功。 知道结果如此,Alice 也没理由再尝试。
自身双花变体 一种更微妙的情况是:Alice 同时扮演 Bob 的角色。 也就是说,她向 Charlie 支付一笔交易,同时又在另一笔交易中把同一枚 infocoin“支付”给自己(本质上是要收回)。这看起来似乎容易检测,但在网络中,一个人可以轻易创建多个身份,因此必须考虑这种可能性。在这种情况下,Alice 的策略如下:她先让 Charlie 收到并确认交易(即在最长链上得到 6 次确认), 等 Charlie 相信交易已不可逆时, Alice 再尝试从该交易之前的某个区块发起新的分叉, 并在新分叉中加入一笔交易—— 把那枚 infocoin 支付给自己。
作者的思考题
- 我不太明白,为什么不能用更简单的方式(比如两阶段提交,two-phase commit)来防止双花(double spending)。假设 Alice 想同时把同一个 infocoin 支付给 Bob 和 Charlie。 一种思路是:Bob 和 Charlie 各自向 Infocoin 网络广播他们收到的交易请求,并附带一个询问:“我应该接受这笔交易吗?”他们随后等待一段时间——比如十分钟——看看是否有人提出异议(“naysayer”),证明 Alice 正在企图双花。 如果在这段时间内没有人提出反对意见(并且没有明显的网络攻击迹象),他们就可以接受这笔交易。 当然,这个协议需要加固以抵御网络攻击,但在我看来,它似乎是一个不错的替代方案的核心思想。 问题是:这种方法到底能否有效?与完整的 Bitcoin 协议相比,它有哪些优点和缺点?
- 本节前面我提到过,有一种“自然的方式”可以降低验证一块交易所需时间的方差(variance)。 但如果这种方差被降低得过多,就会出现一种有趣的攻击可能性。 设想 Alice 试图以以下方式分叉(fork)区块链:(a) 一条分叉链以一个她“支付给自己”的区块开始,另一条分叉链以一个她“支付给 Bob”的区块开始; (b) 这两个区块几乎同时被广播,因此大约有一半的矿工会在每条分叉链上挖矿; (c) Alice 使用自己的算力维持两条分叉链长度大致相等,优先在较短的分叉上挖矿—— 这在通常情况下很难做到,但如果“验证区块所需时间的标准差”远小于“网络传播延迟”,则会容易得多 (d) 当两条分叉链上各自已经有 5 个区块被挖出后,Alice 将算力集中到包含 Charles 交易的那条链上,使那笔交易更有可能被确认; (e) 当 Charles 的交易被确认后,她再把计算能力转移到另一条分叉链上,尝试重新取得领先。这种“平衡策略”(balancing strategy)虽然成功概率仍然很低,但与标准协议(即验证时间方差较高的情形)相比,成功概率会显著提高。 问题是:有没有办法避免这种潜在问题?
- 再假设比特币挖矿软件总是从 nonce = 0 开始尝试,然后依次递增 nonce = 1, 2, ....。 如果所有矿工(或相当大一部分矿工)都采用这种顺序,那么系统就会出现漏洞: 攻击者只需从更大的 nonce 开始搜索,就可能在一定程度上提高自己找到解(proof-of-work)的概率。 更一般地说,只要矿工在探索 nonce 空间时存在某种系统性规律(systematic pattern), 攻击者就可能利用这一规律来提升成功率。再广义一点,本节分析中我默认假设了所有矿工之间是“对称的”(即没有谁比谁更有结构性优势)。 但在现实中,矿工之间的确存在各种不对称
比特币
关于匿名性很多人声称比特币可以匿名使用,这导致了诸如 Silk Road(丝绸之路)这样的非法市场出现。 但这种“匿名”其实是个神话。 区块链是公开的,任何人都可以看到每一笔比特币交易。 虽然地址未直接关联真实身份,但计算机科学家已经证明,通过社交网络去匿名化(de-anonymization)的技术, 可以在很高置信度下推测出用户身份。 NSA 等机构很可能早已在这么做。 实际上,比特币可能是世界上最公开透明的金融系统。
论文阅读: 比特币——P2P电子现金系统
摘要
一种完全点对点的电子现金系统,将允许P2P在线支付,而无需经过金融机构。数字签名可以解决部分问题,但如果仍需要一个可信的第三方来防止“双花”,那么主要的优势就会丧失。我们提出了一种通过点对点网络来解决双花问题的方案。
该网络通过将交易进行哈希,并整合到一个持续增长的、基于工作量证明(proof-of-work)的链条中,为交易加上时间戳,形成一个记录。这种记录在不重新完成工作量证明的情况下无法被更改。最长的链不仅证明了事件发生的顺序,也证明了它是由最大规模的 CPU 算力池生成的。只要大多数 CPU 算力掌握在不试图攻击网络的节点手中,他们就会生成最长的链,并超过攻击者。该网络本身结构极简,消息以尽力广播的方式传播,节点可以随时加入或离开网络,只需在回来时接受当前最长的工作量证明链,作为他们离线期间发生过的事情的凭证。
1. 介绍
互联网商业几乎完全依赖金融机构作为可信第三方来处理电子支付。虽然这个系统对大多数交易来说运作尚可,但它仍然存在基于信任模型的内在弱点。完全不可逆的交易几乎无法实现,因为金融机构无法避免介入争议的调解。调解的代价提高了交易成本,限制了最低可行的交易金额,从而阻碍了小额、随意交易的可能性。
我们真正需要的是一个基于密码学证明、而零信任的电子支付系统,使任何两个愿意交易的个体都能直接进行交易,无需可信第三方介入。这种系统中,计算上不可逆的交易将保护卖家免受欺诈,而常规的托管机制也可以轻松实现,以保护买家。
在本文中,我们提出了一种解决双花问题的方案,使用P2P分布式时间戳服务器来生成交易按时间顺序发生的计算性证明。只要诚实节点集体控制的 CPU 算力超过任何一组协同行为的攻击者节点,该系统就是安全的。
2. 交易
我们将电子货币定义为一个数字签名链。每一位拥有者通过对前一笔交易的哈希值以及下一位拥有者的公钥进行数字签名,并将这些信息添加到这枚“货币”的末尾,从而将该货币转移给下一个人。收款方可以通过验证这些签名,来确认这笔货币的所有权链条。【可推测的信息,1)货币被编码了,2)要交易下一笔,你需要有货币序列号,前一笔交易的指针,已经下一个拥有者的公钥,感觉可以理解为地址。3)每个货币都有自己的链条】
“一枚币” 实际上是一个从最初创建开始的交易链条,假设Alice → Bob → Charlie → Dave,每一笔转账都用上了一个持有者的私钥签名,并把下一个持有者公钥写进交易中。假设最初有一枚币属于 Alice,Alice转给Bob时,创建了一个交易Tx1, 包含输入——他当前拥有的那块币;输出——Bob的公钥;Alice用自己的私钥签名该笔交易,整个交易被广播到网络中。

问题在于:收款方无法验证某一位拥有者是否曾对这枚货币进行了“双花”。常见的解决方案是引入一个可信的中央权威机构(或称“造币厂”),由它来检查每一笔交易是否存在双花。在每次交易之后,货币必须返回造币厂以便重新发行,只有直接由造币厂发行的货币才被信任为没有被双花过。这种方案的问题在于:整个货币系统的命运都依赖于运行造币厂的那家公司,而且每一笔交易都必须经过它,就像传统银行一样。
我们需要一种机制,让收款方能够知道以前的拥有者没有签署过其他更早的交易。对于我们的目标来说,最早的交易才是有效的交易,因此我们并不关心之后的双花尝试。而要确认某一交易不存在的唯一方式,是必须知晓所有交易。在基于造币厂的模型中,造币厂掌握所有交易记录,并决定哪一笔交易最先到达。若要在没有可信方的情况下实现这一点,交易必须被公开广播,并且我们需要一个系统,使参与者能够就交易被接收的顺序达成一致的单一历史记录。收款方需要有一个“证明”,证明在每次交易发生时,网络中大多数节点都同意这是一笔最早被接收到的交易。
3. 时间戳服务器
我们提出的解决方案从一个时间戳服务器开始。时间戳服务器的工作方式是:对一组需要加时间戳的数据进行哈希,然后将这个哈希值广泛公开,例如发布在报纸或 Usenet 论坛上。这个时间戳可以证明数据在那个时间点必须已经存在,因为它才能被包含进那个哈希中。
每一个时间戳在其哈希中都包含了前一个时间戳,从而形成一个链条,每一个新增的时间戳都会强化之前的时间戳

4. 工作量证明
为了以点对点的方式实现分布式时间戳服务器,我们需要使用一种类似于 Adam Back 的 Hashcash 的工作量证明(Proof-of-Work)系统,而不是依赖报纸或 Usenet 论坛发布。
工作量证明的过程是:不断尝试寻找一个数值(例如用 SHA-256 进行哈希时),使得最终的哈希结果以若干个前导零比特开头。所需的平均计算工作量随着要求的零比特数量呈指数级增长,但一旦找到,验证只需要执行一次哈希即可。
在我们的时间戳网络中,我们通过不断递增区块中的 nonce 值来实现工作量证明,直到找到一个满足零比特要求的哈希值。一旦为了满足工作量证明而消耗了 CPU 计算资源,这个区块就不能被更改,除非重新进行相同数量的计算。随着更多区块被接在它后面,想要更改该区块,就必须连同其后的所有区块一起重新计算工作量证明。

工作量证明还解决了在多数决策中如何确定代表性的问题。如果我们以“一个 IP 地址等于一票”为基础来做决策,那么任何拥有大量 IP 的人就能破坏系统。而工作量证明本质上是“一个 CPU 等于一票”。多数决策由那条投入了最多工作量的最长链来表示。
只要大多数的计算能力掌握在诚实节点手中,那么这条诚实链就会增长得最快,压过任何竞争的恶意链。
如果攻击者想要修改一个过去的区块,他必须重做该区块及其之后所有区块的工作量证明,并且还要赶上并超过诚实节点链上的总计算量。我们将在后文展示:攻击者在这种“追赶游戏”中成功的概率,随着新区块的添加将呈指数下降。
为了应对硬件性能不断提升以及参与节点数量随时间变化的问题,系统通过一个滑动平均机制来动态调整工作量证明的难度,使其保持在一个每小时平均产生固定数量区块的目标。如果区块生成速度太快,系统就会提高难度。
5. 网络
运行的网络的步骤如下:
- 新的交易会被广播到所有节点。
- 每个节点会把收到的新交易收集成一个区块
- 每个节点都在为自己的区块寻找一个困难的工作证明
- 当某个节点找到工作量证明时,它会把该区块广播给所有节点
- 各节点只有在区块中所有交易都有效、且并未被花费过的情况下,才会接受这个区块
- 节点通过在下一个区块中引用该区块的哈希作为”前一块区块哈希“,来表达自己对该区块的认可
节点始终认为最长的链才是正确的链,并持续尝试扩展这条最长链。如果两个节点几乎同时广播了不同版本的下一个区块,那么有些节点可能先收到其中一个区块,有些节点先收到另一个。 这种情况下,各节点会继续在它们最先收到的那条链上工作,同时保存另一条分支,以防它后来变得更长。 当下一个工作量证明被找到并使某条链更长时,所有之前在较短分支上工作的节点都会切换到这条更长的链上。
新交易的广播并不要求必须到达所有节点。只要到达了足够多的节点,它们就会很快被打包进某个区块中。区块广播对消息丢失也有一定容忍性: 如果某个节点没有收到某个区块,当它收到后续区块并意识到自己漏掉了一个时,会主动请求补回那个区块。
6. 激励机制
按照约定,每个区块中的第一笔交易是一种特殊交易,用于生成一枚新币,这枚新币归创建该区块的节点所有。这种设计:1)为节点提供了维护网络的激励;2)同时提供了一种将货币投入流通的方式,因为系统中没有中心机构负责发行货币。这种“以恒定速度发行新币”的方式可以类比为黄金开采: 矿工通过消耗资源(在这里是 CPU 时间和电力)来将新的黄金(比特币)加入流通。
激励也可以来自交易手续费。 当一笔交易的输出值小于输入值时,这个差额就是交易费,它会加入到打包该交易的区块奖励中。 当系统中已发行的货币数量达到预定上限后,激励机制就可以完全转变为由交易手续费提供,从而实现零通胀(inflation-free)。
这种激励机制也能鼓励节点保持诚实。假设某个贪婪的攻击者拥有比所有诚实节点加起来还强的计算能力,他必须在两种选择之间做出决定:
- 用这些算力欺骗系统、窃取自己已经支付出去的币;
- 或者用它来诚实地挖矿、赚取新区块奖励。
理性的选择是遵守系统规则, 因为只要他诚实挖矿,就能持续获得比其他所有人加起来还多的新币奖励。如果他攻击系统,不仅破坏了系统的稳定性,还会动摇自己所持财富的价值。
7. 回收磁盘空间
一旦某个币的最新交易被足够多的区块掩埋(即在区块链中有足够的后续区块确认),其之前的已花费交易就可以被丢弃,以节省磁盘空间。为了在不破坏区块哈希的前提下实现这一点,交易被组织成一个梅克尔树(Merkle Tree),并且区块哈希中只包含树根(Merkle Root)。这样,旧区块就可以通过截断树的分支来进行压缩。树的中间哈希值无需保存。一个不包含交易的区块头大约是 80 字节。假设每 10 分钟生成一个区块,那么一年产生的数据量为: 80 字节 × 6 × 24 × 365 = 4.2 MB。

截至 2008 年,计算机系统通常配备 2 GB 内存,而摩尔定律预测内存容量每年增长约 1.2 GB。 因此,即使所有区块头都保存在内存中,存储空间也不会成为问题。
8. 简化支付验证

在不运行完整网络节点的情况下,也可以验证支付。用户只需要保存最长工作量证明链(Proof-of-Work chain)的区块头副本即可。这些区块头可以通过向网络节点查询获得,直到用户确信自己拥有的是最长链。然后,用户再获取将交易与其所在区块关联起来的梅克尔分支(Merkle branch)。用户无法独立验证该交易本身,但通过将交易关联到链上的某个位置,可以确认该交易已被某个网络节点接受; 并且,随着其之后继续被添加的新区块增多,可以进一步确认整个网络已经接受该交易。因此,只要网络由诚实节点控制,这种验证方式就是可靠的;但如果网络被攻击者掌控,这种方式就更容易受到攻击。
虽然网络节点可以自己验证交易,但简化验证方式可能会被攻击者伪造的交易所欺骗,只要攻击者能在一段时间内持续压制整个网络即可。一种防御策略是:当网络节点检测到无效区块时,向用户发出警报,促使用户的软件下载完整区块及被警报的交易,以验证是否存在不一致。对于那些频繁接收支付的商家而言,他们可能仍然希望运行自己的节点,以获得更独立的安全保障和更快的验证速度。
9. 组合与拆分价值
虽然从技术上讲,可以逐个处理每个“硬币”, 但如果每分钱的转账都需要单独一笔交易,那会非常笨重。
为了让价值可以被拆分与合并,交易中允许包含多个输入(inputs)和多个输出(outputs)。 通常情况下,一笔交易可能有:
- 一个来自之前较大交易的单一输入,或
- 若干个输入,用来合并多个较小金额。
而输出则通常最多只有两个:
- 一个用于支付收款方;
- 另一个(若有)用于找零,返回给发送方。
需要注意的是,这里提到的“扇出”(fan-out)情况—— 即某笔交易依赖于多笔其他交易,而那些交易又依赖更多交易—— 并不会带来问题。
因为系统从来不需要提取某笔交易的完整独立历史记录。
10. 隐私性

传统的银行模式通过将信息访问权限限制在交易双方和受信任的第三方,从而实现一定程度的隐私保护。
在比特币中,由于必须公开所有交易,这种方法不可行,但仍可以通过另一种方式保持隐私:让公钥保持匿名。 公众可以看到有人向另一个人发送了一定金额,但无法获得将交易与任何人关联的信息。
这类似于证券交易所公开的信息水平:交易的时间和金额(即“行情记录”)是公开的,但交易双方是谁并不透露。
作为额外的防护措施,每笔交易都应该使用新的密钥对,以防止交易被关联到同一拥有者。 不过,对于多输入交易,某些关联仍不可避免,因为它们必然会揭示这些输入属于同一个拥有者。 风险在于,如果某个密钥的拥有者被揭示,那么通过关联分析可能揭示该拥有者的其他交易。
12. 结论
我们提出了一个无需依赖信任即可进行电子交易的系统。我们从通常的数字签名“硬币”框架出发,这提供了对所有权的强控制,但如果没有防止双花的手段,这一框架是不完整的。
为了解决这个问题,我们提出了一个使用工作量证明(proof-of-work)的点对点网络,用来记录交易的公开历史。如果诚实节点控制了大多数 CPU 计算能力,攻击者几乎不可能改变这段历史。
该网络以其非结构化的简单性表现出高度的稳健性。节点几乎无需协调即可同时工作。节点不需要身份识别,因为消息不需要路由到特定地点,只需尽最大努力传递即可。节点可以自由离开或重新加入网络,并在加入时接受工作量证明链,作为它们离开期间发生事情的证明。
节点通过其 CPU 计算能力进行“投票”:通过扩展有效区块来表示接受,通过拒绝扩展无效区块来表示拒绝。任何必要的规则和激励机制都可以通过这种共识机制来强制执行。