查看原文
其他

比特币系统是如何运行的?

The following article is from 金融极客 Author 金融极客Graylamb

这是量信投资公众号的首篇授权转载文章(注:原作者禁止一切未授权转载,如有转载需求请联系原作者)。


原则上,我们不会转载任何文章(因此这也可能是本公众号的最后一篇转载文章)。我们认为微信上 99.999...% 的文章都并不是试图把一个问题说明白。因此,与其转发,不如自己写,力争把一个东西掰开揉碎、给读者说清楚。但是,我认为有必要为了今天这篇文章——关于比特币——破个例。


近日,比特币冲破了 4000 美元大关;今年之内其涨幅更是超过 300%。它似乎已经代替黄金称为避险资产的首选;任何人都无法忽视它的存在。


那么,到底何为比特币,它有着怎样的“前世今生”?关于它的诸如“Hash 碰撞、挖矿、矿机”等术语又是什么意思?今天,我们就为关注量信投资的朋友送上一篇关于比特币的福利。


本文的作者(Graylamb,公众号:金融极客)是我的一位靠谱挚交,他潜心在国有某大型银行工作十余载,精通比特币系统、并亲自挖掘过比特币。他花了两个月的时间书写、整理、措辞、反复推敲,最终完成了下面您将看到的这篇《比特币系统是如何运行的?》。


关于知识的分享,本文作者和我有同样的价值观:写作是以将知识明明白白清清楚楚的传递给读者为唯一目的;每一个用词都应该是清晰的,没有半点含糊不清的。


注意,本文虽然深入浅出,但毕竟涉及到的话题——比特币系统——十分 technical,因此,读起来还是有一定“痛苦”的。比特币毕竟不是王者荣耀对不对?一个是赚钱的;一个是花钱的!而且,任何静下心来学习的过程都是痛苦的(这当然和我们在什么《得到》 APP 上订阅个频道、交点智商税、听段子、产生剔除焦虑感的幻觉不一样)。想要搞清楚比特币这类概念,就应该有“痛苦的觉悟”。否则,我们永远只知道“显卡”、“挖矿”这些肤浅的词汇。


如果你静下心来认真看完今天的文章(而不是点了收藏然后就没有然后了),我相信比特币对你不再神秘。


言归正传,以下就是正文部分。


前言

这篇文章主要讲解比特币是什么?它的运行原理是什么?


比特币与其说是计算机学的成功,不如说是密码学的成功。在它的基本运行原理中,运用了太多密码学的经典知识。本文也是从私钥、公钥、Hash 算法等密码学知识出发,深入浅出的全面剖析了比特币的运行方式。而像 Json,Merkle Tree,Bloom 过滤器等计算机学的知识就显得不那么关键了,在文中也就不过多介绍了,如果想了解也可以给我留言,一起交流。


写这篇文章时,花心思最多的地方就是文章的讲述逻辑。我一直认为技术文章从来就是不好读的,但如果有一个好的逻辑,有了“前因后果”、“深入浅出”,也许你读起来也就没那么抵触了。当然说起来简单,做起来难。由于比特币的运行原理非常的复杂,难以找到一条完美的讲述线索,现在你看到的文章,也是几经修改后的成果。希望它能帮你掌握比特币复杂的技术原理。


1

什么是比特币


比特币是一种在网络世界里的电子货币、虚拟货币。



而“电子”货币跟你手里的纸币的区别就是:它没有实体,它只是计算机世界里的一串数字。


可能你会说:没拿到手里的钱还是钱吗?我觉得“电子”货币根本不能用来买东西的。但为什么不能呢?就因为它是计算机世界里的一串数字,就不能用来买东西了?



这很可能是每个人的直观感受:一串计算机里存储的数字,它没有任何价值啊,我们为什么要接受它,并把我的有价值的商品给对方?


可是想想你手里的钞票吧,它也只是一张普普通通的纸而已,一张纸的实际价值不比计算机里的数字高多少吧~那你为什么就相信这张纸了呢?


所以关键点在这里:一种货币能不能用来买东西,不是它自身的价值决定的,而是你身边的每一个人是否相信这种货币?如果大家都相信这种货币,不论这个货币是什么形态的,都可以用来买东西。


与“是否能信任电子货币”相对应的是,手里的纸币就值得人们信赖吗?一个国家的纸币是由这个国家央行发行并提供信用担保的,也就是由国家确保你手里的纸币一定能够花出去。但是如果国家耍无赖,你手里的纸币也会贬值,甚至一文不值。那些提着一塑料袋钞票才能买到一个鸡蛋的国家,是真实存在的。


那么为什么大家会相信比特币?我们在下一章节展开介绍。


2

为什么信赖比特币


1、你会相信什么样的货币?


一种货币,如何才能让大家都信赖它呢?


最重要的一点,当然就是这种货币是否可靠!人们对于一种货币是否“可靠”的最初认知就是:看得见摸得着。


回想一下你们的长辈,是不是有过“把钱存在银行不安全,压在箱底才最安全”的想法?这就是老一辈人对于“可靠”的理解。甚至后来,即便大家开始接受把钱存在银行中,但老一辈人仍然更倾向选择更像货币实物的存折,而非银行卡。他们感觉每月明细清清楚楚打在折子上会让人更加放心,而如果是银行卡,则只能到柜面让柜员帮你查到里面的内容(那时 ATM 还少的可怜,更没有什么网银、手机银行云云)。因此,即便手里已经没有钞票了,即便钞票已经变为了存折本上一行行密密麻麻的小字,也要拿在手里看在眼里最有安全感。这就是对于货币实物的依赖。


但是随着时代的发展,越来越多的人开始接受看不见的货币了。拿到钱先存到银行是最普遍的做法,而且存折在很多银行已经开始退出历史舞台。通过转款等非现金交易的方式在大额交易中已经非常普遍,现如今,用手机微信零钱包里的一串数字作为零钱进行支付的方式,大家也已经习以为常了。



为什么老一辈人觉得“看得见摸得着”更有安全感?因为在哪个年代,只有货币在我的手中,才能控制好两件事情:


1、我手中(收到)的货币数量是不可被更改;

2、只有我的授权才能支付。


看得见摸得着 = 我手中(收到)的货币数量不可被更改 + 只有我的授权才能支付


后来,人们开始逐渐信任银行,并把“看得见摸得着”的钱存入银行,这是因为银行具备保证“我手中(收到)的货币数量不可被更改+只有我的授权才能支付”的能力。银行通过建立庞大的IT系统,存储每个客户资金的数据,确保这些数据不被篡改,并通过技术手段确保资金在得到所有者的授权后才能支付。所以在银行的系统里,通常会有一个存储了所有储户账户余额的表单,我们把它叫做 Ledger,即账本。就像下面这样:



Ledger 告诉了我们,Alice 有 5.3 元,Bob 有 100 元……银行会投入大量的精力和物力去保证系统中这张表的准确性,确保每个人对应的金额不能随意的增减。他们建立自己的机房、搭建独立的网络环境、购买最先进的服务器、聘请最资深的专家。也正是因此,我们才相信银行能够保证 Ledger 的准确性,于是我们就把钱存到了银行。


后来,就像相信银行存储的 Ledger 一样,我们还同样相信政府存储的每个人的社保信息,相信支付宝里的余额信息,相信微信里的零钱信息。


渐渐的,我们的“身家性命”真的全部变成了这些机构服务器上存储的一个文件、一串数据。这些机构也在想尽办法让自己的数据更加的安全、系统更加健壮,比如:采用各种数据备份机制、采用分布式存储技术……但即便如此,也偶有灾难事件发生。


于是人们开始思考一个问题:是否可以有一种不依靠某一家机构的人力、物力、技术能力,而是借助整个互联网的力量,为每个人的财富数据提供保障的方案呢?


就这样,比特币出现了!


2、比特币去中心化的存储机制


与传统的存储方案不同,比特币采用了一种特殊的去中心化的账本存储方案。简单说就是:所有加入比特币网络的电脑上,都会存储一份这样的账本。



由于账本存储在网络的各个节点上,其中一个节点出现问题,还是可以从网络上的其他节点获取到正确数据的。可以对比一下传统中心式的存储体系与比特币去中心化的存储体系的区别。



由于这种去中心化存储账本的特点,在某一个节点更新账本数据的时候,就要通知其他节点一起修改账本记录。举一个例子,如果 Alice 给 Bob 转了 5 个比特币(BitCoin,也称做 BTC),那么最初进行这笔转账处理的节点,就要把这个处理的情况传播给临近的其他节点,然后其他节点再传播给临近的节点……直到网络上所有的节点账本都被更新了。



3、比特币交易——如何实现“只有我的授权才能支付”


在这种去中心化的环境下,没有银行这种机构的统一管理,不需要建立服务器集群或聘请庞大的维护团队,所有比特币的交易业务都是基于预先设定好的程序或算法,在互联网上自发生长。


那么,在这样一种去中心化的环境中,如何能保证收款和支付的安全性,最终达到“我手中(收到)的货币数量不可被更改+只有我的授权才能支付”的目标呢?


首先,来看“只有我的授权才能支付”这一点,比特币是用“私钥”和“公钥”来实现的。


“公钥”“私钥”是现代密码学非对称性加密里面的概念,而非对称性加密又与对称性加密相对应。对称性加密中只有一个密钥,即用来加密又用来解密。比如以前战争年代常用一本密码字典(比如什么字对应哪本书中的第几页第几个字)把一句话加密为密文。这本密码字典就是密钥,可以看出密钥十分关键,如果密钥泄露,那拿到密钥的人就可以进行解密。这种加密方式的缺点显而易见,你要让对方解密你的密文,就要把这个密钥也给对方,这样就极大的增加了密钥泄露的概率。


这一情况,直到非对称加密出现后才得到改观!


非对称加密中,每个人都有两个密钥,一个“公钥”,一个“私钥”。“公钥”是公开的。而私钥只有自己手里才有。“公钥”、“私钥”的特点可以简单理解为:用一个人的“公钥”加密,只能用这个人的“私钥”解密;而用一个人的“私钥”加密,只能用这个人的“公钥”解密。


这样,就解决了传递“密钥”过程中,“密钥”泄露的问题。因为如果我想给你一个只有你能看的信息,因为我手里有你的“公钥”,而你的“私钥”只在你手里才有,因此我只要用你的“公钥”加密就行了。


比特币系统就是采用了这一加密方式。但你可能会好奇,比特币系统里的“私钥”、“公钥”机制是怎么实现的?


简单来说,比特币系统让每个参与交易的人,先随机产生一个字符串,作为自己的唯一的“私钥”。然后会通过“私钥”生成对应的唯一“公钥”。生成后,“公钥”在比特币网络上公开给每个人,而“私钥”你要自己藏好,不能让别人知道。由于“私钥”生成“公钥”的过程是不可逆的,因此别人即便拿到了你的“公钥”,也不可能知道你的“私钥”是什么。这样,我们很容易就能实现下面的功能:当别人用你的“公钥”锁定一个数据时,只有拥有“私钥”的人(也就是你)才可能解锁这个数据。


注:举个简单(但不实际)的例子,比如你随机生成两个质数(173、881),拼成一个 6 位“私钥” 173881,我们生成“公钥”的规则就是将两个质数相乘 173 × 881 = 152413。这时网络上的人都会拿到“公钥” 152413。当某个人想让某个数据只能被你修改时,他可以在这段数据后面加上“公钥” 152413,并声明,只有私钥左 3 位乘右 3 位等于公钥的人,才可以修改这个数据。这样也就只有你能修改这个数据了。 如果,网络上有个黑客想不经你的同意篡改这个数据,即便黑客知道“私钥”生成“公钥”规则是两个质数相乘,他也不知道是哪两个质数,因此,他只能进行 X 乘 Y 的暴力破解找到“私钥”: 001 × 001, 001 × 002, 001 × 003, 002 × 001, 002 × 002 ……。当质数很大时这个过程是比较艰难的。 当然上面例子中所使用的规则太过简单,用计算机暴力破解是可以很快通过“公钥”找到“私钥”的。但是比特币系统使用的椭圆曲线算法从“私钥”生成“公钥”,现有技术手段很难破解。同时,实际的比特币系统中私钥解密过程也是很复杂的,是通过一种基于逆波兰表示法的堆栈执行语言实现的。如果有兴趣深入了解,你可以 Google 一下或者翻阅《精通比特币》一书。


好了,明白了比特币系统中的“公钥”和“私钥”原理后,后面理解起来就会容易很多。


我们把参与转账的人变得多一些,假设有 3 个人,Charles 先给 Alice 转了 5 个 BTC,然后,Alice 又把这 5 个 BTC 转给了 Bob。


我们站在 Alice 的位置进行分析,Alice 为何能给 Bob 转这 5 个 BTC 呢?因为 Alice 能够用自己的“私钥”解锁这 5 个 BTC。而这 5 个 BTC 是如何锁定的呢?聪明如你一定想到了,Charles 给 Alice 转帐时用 Alice 的“公钥”锁住了这 5 个 BTC。


而 Alice 再给 Bob 转账时,又用 Bob 的“公钥”把这 5 个 BTC 给锁定了。只有当 Bob 要用这 5 个 BTC 时,才能用自己的“私钥”解锁并使用这 5 个 BTC,其他人因为没有 Bob 的“私钥”,是不能动用这 5 个 BTC 的。


所以,比特币系统里很智慧的一点:就是把一个人的“公钥”当作这个人的收款账号(或收款地址)。这样当你在给别人转账时,你输入了别人的收款账号——也即别人的“公钥”,比特币系统会自动帮你把这笔款用那个人的“公钥”锁定。这样这笔钱就属于他了,将来他必须用他的私钥解锁,才能使用这笔钱。这样也就达到了“只有我的授权才能支付”这一点。


注:其实公钥到收款地址还需要做一些转换,本文为了写得简单易懂就忽略这些细节了,但是收款账号与公钥是有极强的相关性的。


神奇吧,钱并没有实际握在你的手里,只是存在于比特币的网络里,但它就是属于你!


看到这里,我想你应该不介意再趁热打铁多了解一些比特币交易数据结构方面的知识,因为这对你后面知识的理解会很有帮助。


上面提到,Alice 给 Bob 转账,既要用 Alice 的“私钥”解锁,又要通过 Bob 的“公钥”加密,因此,比特币交易的数据结构分为 inputs 和 outputs 两部分:


inputs 主要是 Alice(这笔转账的输入方,也即”发起方")的信息,主要包括:


ScriptSig——Alice 的数字签名信息,即:Alice 的“私钥”信息的 Hash 值,这个 Hash 值里包含了“私钥”的特征,是用来“解锁”用的。(如果你不明白 Hash 值是什么,不要紧,在这里并不关键,而且后文会详细介绍 Hash 值)


outputs 主要是 Bob(这笔转账的输出方,也即“接受方”)的信息,主要包括:.


Amount——金额


scriptPubKey——用 Bob “公钥”生成的一段锁定脚本,里面包含着 Bob “公钥”的特征,将这笔金额锁定后,只有含有 Bob “私钥”特征的签名信息才能够解锁。


你有没有觉得少点什么?对了,上面的数据结构里只有 Alice 的“私钥”信息,却没有 Alice 的“公钥”信息,如何能实现对 Alice “私钥”与“公钥”的匹配,从而实现解锁呢?


原来,在 inputs 里,还要有一个交易序号(txn),这个 txn 代表 Charles 给 Alice 转 5 个 BTC 的那笔交易,因为在那笔交易里,Alice 是接收方,交易的 outputs 里面有 Alice 的“公钥”地址。


当 Alice 使用比特币时,比特币系统会从 Alice 给 Bob 转账的交易中,找到 Alice 的 ScriptSig(相当于是“私钥”),再通过这个交易里记载的上一个交易的 txn,顺藤摸瓜找到上一个交易中 Alice 的 scriptPubKey(相当于是“公钥”),然后进行“私钥”和“公钥”的验证,验证通过后,Alice 才有权使用这 5 个比特币,Alice 给 Bob 转账的交易才能成功。


讲到这里,你应该已经了解了比特币系统中,交易数据是什么样子。它们绝大多数都是下面这个样子的:


inputs
   txn: 我要转出的比特币是从哪笔交易来的?
   scriptSig: 用我的“私钥”生成的解锁脚本,以便解锁我要转出的比特币。

outputs
   Amount:我要转出的比特币金额多大?
   scriptPubKey: 将这笔金额用收我钱的那个家伙的“公钥”锁定。


而且你可以通过 txn 一直追溯下去,一直追溯到这笔比特币的源头:



到这里,又出了个新问题,如果 Alice 转给 Bob 的交易是 5 个 BTC,那这笔交易的上一笔交易一定也必须是 5 个 BTC 吗?



比特币系统给了你一个很灵活的处理体系,在这个体系下,inputs 可以是多笔.


例如下面这个例子,Bob 收到了 Alice 的 5 个 BTC,这 5 个 BTC 是由 Charles 给 Alice 的 3 个 BTC 和 Fred 给 Alice 的 2 个 BTC 组成的。当然 Alice 收到的这两笔转账交易一样有它们之前的交易,Fred 给 Alice 的 2 个 BTC 是通过一笔之前的交易得到的(inputs 里有一笔交易 txn#772...),而 Charles 给 Alice 的 3 个 BTC 是通过两笔之前的交易得到的(inputs 里有两笔交易 txn#343...,txn#05a...)。



在真实的比特币网络中,你会看到更为复杂的交易结构,比如下面这笔交易,它是由 6 笔交易作为 inputs。6 笔交易总共的比特币金额是 139.616 BTC。接下来,你会发现一个有趣事情,就是这笔交易的 outputs 对应多个“公钥”脚本(也就是多个收款地址):一个是收款方“公钥”信息,一个是你自己的“公钥”信息。收款方“公钥”信息的 Amount 是 139.606 BTC,你自己“公钥”信息的 Amount 是 0.01 BTC。它的意思是:前面汇款给我的 6 笔交易总共包含 139.616 BTC,我只要支付其中的 139.606 BTC 给收款人,剩下的 0.01 BTC 用我自己的“公钥”信息锁定,也就相当于将剩下的“零钱”转回给我自己。



看到这里,你已经了解了比特币交易的主要特点了。比特币网络里充斥着这样数以千万记的比特币交易,交易间通过交易序号 txn 连接起来,通过这些由交易序号串联起来的路径,你可以了解你拿到的比特币从哪来的?要到哪里去?编织成一个错综复杂的支付路径。



4、比特币账本——如何实现“我手中(收到)的货币数量不可被更改”


还记得上一节中我们提到的账本 Ledger 吗?



保证“我手中(收到)的货币数量不可被更改”也意味着保证账本中我的账户余额不能被随意的篡改。这是怎么实现的呢?


其实,在比特币系统中,这张 Ledger 中没有每个人的余额,有的只是那几千万条交易:



那每个人的余额怎么来的呢?是的,就是你想到的最麻烦的办法,比特币系统按照每个人的收款地址(相当于每个人的“公钥”),将这个收款地址下所有的转入、转出额度加总,就得到了这个收款地址的余额了。比如:下面例子中,一个以 13kjhfg 开头的收款地址,他的余额就是这么一点一点累加出来的。



这样的账本下,你的余额是无法篡改的,或者说,如果你要篡改余额,那就必须伪造交易。但是从前面的文字,你应该也明白交易与交易之间的关系是多么的紧密,随便伪造一笔交易是十分困难的。下面的章节会进一步说明伪造、篡改交易的其它困难。


5、区块链上的交易为何无法伪造或篡改?


1)伪造最近的一笔交易


如果你想伪造最近的一笔交易,那么很不幸,几乎是不可能的。


还记得上文我们提到的比特币交易结构吗?每一笔比特币交易都能够追溯到它的上一笔交易。因此,下面的例子中,当 Alice 从其他 3 笔交易中分别收到 1 BTC、2 BTC、2 BTC 后,将这 3 笔交易作为 inputs,向 George 发起一笔 5 个 BTC 的转账时,比特币系统会先去往 Alice 收到 BTC 的 3 笔交易中,检查一下 Alice 是否已经用过这 3 笔交易中的 BTC。只有这 3 笔交易中的 BTC 都未曾被支付过时,比特币系统才认为 Alice 向 George 的转账是合法的。



“检查 Alice 收到的 BTC 是否被支付过”在比特币系统中是很好实现的,只要先找一下哪些交易的 outputs 中含有 Alice 的地址(这些就是支付给 Alice 的交易),然后检查一下它们的交易序号 txn 是否出现在其他交易的 inputs 里(确认这些交易是否被支付过)。


但是在全网千万笔交易的环境下进行这个检查会很耗时,因此比特币系统会生成一个未被支付交易索引,随着每次新交易的产生,这个索引会不断更新:去掉被支付的交易,加入新的未被支付的交易,并随着新交易信息传递给网络上的每一个节点。所以,实际上检查“Alice 收到的 BTC 是否被支付过”时,看一下 inputs 里的交易的 txn 是否在未被支付交易索引中即可。


另外,前文提到的比特币系统对于交易 inputs 和 outputs 的处理方式,也会保证 inputs 的金额之和与 outputs 的金额之和相等,从额保证每笔交易的金额不能随意篡改。



2)篡改历史交易


既然上面提到,每一笔交易与它前一笔交易是紧密相关的,因此新发生的交易等于被旧交易牵制着,也就不能随意篡改、伪造。那你可能有疑问了,那么我是否可以通过伪造或篡改历史交易,将整个交易链条上的交易全部篡改,从而改变你的交易行为以及你的账户余额?



答案是:不可能的。


要了解为什么“不可能”,我们需要先学习一个小知识——“Hash 函数与 Hash 值”。


“Hash 函数”的作用是将一大段文字内容,按照一定的规则输出为一个定长的摘要信息,这个摘要信息即“Hash 值”。这个“Hash 值”只与原来的文字有关,即一模一样的文字的“Hash 值”是一样的,但只要文字稍做修改,“Hash 值”就会变化。由文字生成 Hash 值的过程是不可逆的,也就是说我只能从文字得到 Hash 值,但是从 Hash 值是反推不出代表什么文字的。


如果你觉得不好理解可以想想一串数字求余数的过程,比如我们有个很大的数字:231451723794,拿它对质数 3111117 相除求余数,得到余数 174579。我们就可以把 174579 看成 231451723794 的摘要。此外,如果这时改动 231451723794 中任意一个数字,这个得到的余数极大概率是不一样的,基本实现了数字与摘要的一对一关系。同时,如果先给你余数 174579,你还原回 231451723794 是很难的。


当然,上面的求余数太简单了,每 3111117 个数字,余数就会重复一次。Hash 算法采用了复杂得多的取余数算法,以尽量保证两个不同的文本输出的 Hash 值不一样,并尽量保证 Hash 值不能反推回原始信息。如果很不幸,两个不同的文本输出了同样的 Hash 值,这种情况就叫做“碰撞”。“碰撞”是我们不希望看到的情况,因此,Hash 函数的算法也在不断的更新换代,MD4、MD5、SHA 等等都是不同的 Hash 函数算法,随着算法越来越复杂,“碰撞”的概率越来越低,一次 Hash 运算处理的时间也越来越长。比特币采用的是 SHA256 的 Hash 算法。对于 SHA256 的 Hash 算法,我们来看一个 Hash 函数输出结果的实例:



可以看到,一句话仅仅多了一个句号,它的 Hash 值就大相径庭了。


比特币系统是如何运用 Hash 函数的呢?


比特币系统在进行交易数据存储的时候,会将交易分组打包存储(目前一个包的大小为 1M,而一笔交易数据至少 250 字节,基本上每个包可以容纳近千条交易),这个包就是我们常说的区块(Block)。区块与区块之间,会通过每个区块的特征参数连接起来,即,每个区块都记录了前一个区块的特征参数,形成了一种链式的存储结构,“区块链”这个闻名遐迩的词语就是打这儿来的。



那这个将每个区块都串联起来的特征参数到底是什么呢?



聪明如你一定猜到了,这就是这个区块所包含“内容”的 Hash 值。


一般一个区块中包含哪些“内容”呢?一是上一个区块的 Hash 值,二是一堆交易,三是一个叫做 Nonce 的变量(Nonce 做什么用的后面的章节会详细介绍,这里暂时留下一个悬念)。所以,一个区块的 Hash 值,可以简单理解为对上面三项“内容”求出的一个 Hash 值。


综上,生成一个区块的大致过程基本是这样的:


a、交易发生后进入计算机的内存,先进行一些基本验证(比如:这笔交易的 input 中引用的交易,是否是未被支付过的交易)。若验证不成功,则交易会被认为是 invalid Transaction——无效交易。若验证成功后这些交易会被认为是 Unconfirm Transaction——未确认交易,“未确认交易”会静静的躺在内存的有效交易池中等待被装入区块中。由于前面提到,比特币是一种全网记账的系统,因此这笔交易发生后,也会在全网广播,周边的计算机节点接到这笔交易后,也一样先放入内存,再进行验证,验证通过即等待被打包进区块。


b、比特币网络中负责发起记账动作的节点会从内存的有效交易池中,抽取近千笔 Unconfirmed Transaction,然后进行打包。打包时,会将上一个区块的 Hash 值也加入包中。


c、然后对整个包求 Hash 值,这个 Hash 值就是这个区块的特征参数。这个特征参数很重要的,因为后面再生成新的区块时,还要用到它。


d、由于比特币是一种全网记账的系统,因此,当该节点生成新区块后,整个过程并没有结束,该节点接下来会发起一次全网记账。它会将新区块的数据广播给周边的节点,周边的节点再传递给周边的节点,直到全网都收到这个信息。当周边的节点收到这个信息后,也开始在本地进行一样的处理,即:将新区块数据记录到本地的电脑中,以确保本地的区块链数据更新为最新的数据。



看到这里,你会发现一个有趣的现象,比特币这种链式存储的结构,每一个区块的 Hash 值都是由上一个区块的 Hash 值决定的,因此,如果你要修改了历史上的一笔交易,那么这笔交易所在的区块数据的 Hash 值就会变化,那么引用这个 Hash 值的下一个区块的 Hash 值也要变化,影响一直随着区块链延伸下去。



现在,你应该明白修改历史交易的难度了。修改历史交易并不只是修改几百笔交易那么简单,修改历史交易,意味着该笔交易后面所有的数据记录全部出现不匹配的情况。如果你要调整后面所有的数据让他们匹配起来,这几乎是一项不可能的任务。


6、比特币系统运行机制的高阶知识——双重支付风险与防控机制


看完上面的内容,你已经基本对比特币和区块链的知识有了一定了解。下面的内容就是一些进阶知识了,有兴趣的读者可以继续往下看,有些烧脑但很有意思。


你可能会说,哇,比特币看似无懈可击嘛,无法伪造和篡改交易,余额是每笔交易累起来的,非常的安全。


但事实真的是这样吗?其实还有一种特殊的风险,我们慢慢来分析。


我们先来回顾一下一笔交易发生的过程:


比特币交易发生后,会在自己这个节点进行验证,并同时在全网广播,周边的节点接到广播后,也开始验证。一旦交易验证通过,则更新到各自内存的有效交易池中。


由于在全网广播的过程中,无法控制先到达哪个节点后到达哪个节点,因此,节点先接到哪笔交易,后接到哪笔交易完全是随机的。



比如,上面这个例子中,最右下角那个节点就先接到了后发起的交易。


这样,会存在这样一种情况:Alice 给 Bob 地址转账的同时,又发起了一笔给自己地址的转账。



在交易进行广播的时候,一些节点收到了 Alice 给 Bob 地址转账的交易,另一些节点收到了 Alice 给自己地址转账的交易。于是,先收到 Alice 给 Bob 转账交易的节点,会验证通过 Alice 给 Bob 转账的交易(因为后面来的 Alice 给自己地址转账的交易,会因为 inputs 中的交易已被支付给 Bob 而被拒绝),并放入自己的有效交易池中。类似的,先接到 Alice 给自己转账交易的节点,会验证通过 Alice 给自己转账的交易,并放入自己的有效交易池中,如下图。



这时,网络上的节点分为两个阵营,即 Bob 阵营和 Alice 阵营。


现在我们进入下一步,组装区块。


Bob 阵营的节点会组装出一个区块,接到整个区块链的最后;而 Alice 阵营的节点会组装出另外一个区块,接到整个区块链的最后。这样,比特币系统的区块链就分叉了,出现了两条链,以哪条链为准呢?


按照比特币系统的运行规则,要以最长的链为准


这里,我们再举个直观一些的例子来说明。最开始,比特币网络上相安无事,记录的都是一条统一的链条。




在某一时刻,加拿大的节点发现了一个红色区块,与此同时,澳大利亚的节点发现了一个绿色的区块,它们将新区块接在了链条的最末端,各自开始向周围节点进行广播,它们周围的节点逐步都收到了它们的信息。为了形象,我们把加拿大节点的广播路径显示为红色,把澳大利亚节点的广播路径显示为绿色,可以看到,它们在逐渐把蓝色变为自己的颜色。



最终,网络上出现了两个链条。一部分节点记录着包含红区块的链,一部分节点记录着包含绿区块的链。



这时,红色阵营的节点在不断的尝试在自己链条(即:末尾为红色区块的链条)结尾新增区块,而绿色阵营的节点也在不断的尝试在自己链条(即:末尾为绿色区块的链条)结尾新增区块。


突然,绿色阵营位于俄罗斯的节点发现了新的区块,即粉色区块,于是这个新节点开始了新一轮广播。



这次广播比较有趣,当广播到绿色阵营的节点,绿节点们很开心的在自己链条结尾加上了粉色区块,而当广播到红色阵营的节点,红节点们则立刻倒戈,遗弃掉自己的红区块,而是保留下更长的“绿色区块+粉色区块”的链条。



如果你的交易刚好在被遗弃的区块里,那你这笔交易将被重新扔回内存里!



看到这里你是不是开始有一些担心了?回到 Alice 给 Bob 转账买东西的场景。Alice 给 Bob 转账的交易被记录在区块链中后,Bob 给 Alice 寄出了商品。但就在此时,Alice 生成了一条更长的包含 Alice 给自己转账交易的区块链,这时,那条包含 Alice 给 Bob 转账交易的区块链就会被更长的链所取代。



而 Alice 给 Bob 转账的那笔交易,回到内存中后也进不了有效交易池。它会被认为是一笔 invalid Transaction,而被遗弃掉。因为,在验证时会发现,这笔交易 inputs 里的那笔交易并不是一笔未支付的交易,因为它已被支付给 Alice 自己。结局是,Bob 寄出了物品,却没有收到钱。


这就是比特币里常常提到的双重支付风险(也叫“双花”风险)。


为了解决这个问题,比特币系统就要想出一种办法,让 Alice 不能轻易的制造出更长的链条。


这种办法就是:让所有的节点计算一道很难的谜题,只有找到答案的节点才有权组装新的区块,并发起一次记账动作。


那么这道谜题是什么呢?就是让新区块的 Hash 值小于一个目标值。很难理解吧?来听我慢慢解释。


还记得前面章节提到,每一个区块都会有一个 Hash 值吗?而这个 Hash 值,是通过区块中的三项内容计算出的:一是上一个的 Hash 值,二是一堆交易,三是一个叫做 Nonce 的变量。(讲到这里,Nonce 这个变量终于要闪亮登场了!)


每个节点在组包时,节点会不断的调整 Nonce 的大小,使得由“1. 上一个区块的 Hash 值,2. 一堆交易,3. Nonce 变量”这三项内容组成的文本串发生变化,从而使其对应的 Hash 值也发生变化。


重点来了,Hash 值在不断的变化,而只有当某次计算出的 Hash 值小于目标值的时候,这个节点才能宣布自己解出了谜题,并可以发起一次全网记账动作!而记账的内容呢?就是以“上一区块的 Hash 值、一堆交易、目前的 Nonce 变量值”等信息组成的一个新区块。


举个例子。


一串文本“I am Satoshi Nakamoto”(我是中本聪)如果后面加上一个不断变化的 nonce,那它的 Hash 值也会不断的变化:



假设我们要找到的目标值是以 0 开头的(即小于 10000000....)Hash 值,我们发现,当 nonce 为 13 时即满足了条件。而比特币系统中也是这么做的:



在上面的例子中,我们会发现很快就找到了答案,这是因为题目太简单了。如何加大难度呢?找一个 00 开头,或者找一个 000 开头的 Hash 值肯定更具挑战性。而且前面的 0 越多,谜题也就越难。


在真正的比特币系统中,目标值通常是一个由多个 0 开头的 16 位数字,这就导致每个节点要进行数以亿计次计算,才可以找到满足条件的 Hash。同时,比特币系统还会调整目标值,以达到控制谜题难度的目的。


其实特别好理解的比喻就是扔骰子,你可以看成是节点们在不断的扔 2 个骰子,当扔到小于目标值的数字时就能成功拿到组包记账的权利。而目标值一开始是 12,于是很简单,只要节点们不扔到两个 6 就满足条件。这时比特币系统觉得大家玩的太嗨了,要提高一下难度,于是把目标值调整成 3 了,于是节点们都哭了,因为只有扔到两个 1 才能满足条件。


为什么要控制谜题的难度呢?因为不断有新的节点加入到比特币网络中,解题的节点越多,就越可能在短时间内算出满足条件的 Hash 值。于是,比特币系统就要调整谜题难度,以确保基本每 10 分钟才能解出一次谜题。


这种通过解谜题来确立节点组包记账权的方式,有一个在区块链界响当当的名字——工作量证明 Proof of Work(PoW)


所以,在上面的情况下,Alice是 不可能迅速形成一条更长的链条的。她如果想实现双重支付,就必须与其它节点赛跑。但是她是不可能赢过其它节点的,因为她只有一个节点。


你可能会说,如果 Alice 有一台运算速度很快的电脑呢?或者,有一百台、成千上万台强大的电脑呢?那她也没有取胜的可能,因为她对抗的是全世界所有的节点。



很明显,只有当 Alice 控制了全世界多一半的节点时(如控制了全世界 51% 的节点),她制造出更长的链条的可能性才会更大。这就是一些比特币相关文章中,经常提到的“51% 攻击”。


7、比特币系统运行机制的其它知识


其实讲到这里,比特币系统运行的绝大部分知识就已经介绍完了。下面你看到的一些名词或短语,是你在看比特币文章时可能遇到的,所以也在这里逐一解释一下。


1)节点


看完上面的文字,相信你对于比特币系统全网记账的机制已经有了比较深刻的印象了。在全网记账的过程中,每个节点在里面起到的作用就至关重要。上面提到了节点与节点间会进行交易广播、会进行区块链信息的广播,节点还可以进行记账。其实真实比特币网络中,不同的节点会有不同的功能,下面把比较重要的几种节点简单介绍一下:


a. 全节点:这种节点会将历史上所有的区块数据(包含所有交易)都下载下来,因此,这种节点可以独立的进行比特币地址的余额验证、交易有效性验证、历史交易验证等工作。由于全节点需要保留比特币网络上所有的交易数据,因此它会根据网络上广播的新区块信息,不断的新增最新的数据,保证区块链数据处于最新的状态。由于上述原因,全节点对比特币交易的验证是最安全的。我自己安装的就是这种节点类型的客户端。但是这种节点的缺点也很明显,由于需要下载历史上所有交易数据,这种节点显得特别笨重。根据我自己的经验,2013 年时全节点大小在几十个 G,最近(2017.8)全节点大小已经达到 130G 左右。


b. SPV 节点:由于移动设备的飞速发展,在手机、Pad 等便携设备上进行比特币交易的需求越来越旺盛。显然在存储空间有限的便携设备上,无法安装“全节点”。因此比特币系统支持一种轻量级的节点客户端。这种客户端只会下载区块的关键数据,比如区块的 Hash 值,Nonce 数值等数据。通过这些数据就可以知道区块链概况。这些关键数据只有区块全量数据的 1/1000,因此客户端会显得很轻便。但 SPV 节点的问题是,在进行交易验证时,必须通过网络从全节点处获取验证所需的信息,才可以进行验证。如果你身边有黑客建立的伪节点(如受到 Sybil 攻击),可能会干扰你的验证过程。因此,要保证万无一失的安全性,最可靠的方法还是建立一个“全节点”。


c. 矿工节点:前面讲到,部分节点要通过大量、不停歇的计算,去争取组装区块及发起全网记账的权利(上面提到过,这个过程叫工作量证明 PoW)。这样的工作不是每个节点都要做的,而只有矿工节点才会去做。为什么叫做“矿工”节点呢?因为每次这类节点算出谜题并争取到组包记账的权利时,比特币系统会给这个节点奖励一定数量的比特币。这个过程非常像是一个矿工在很费力的挖矿,奖励的比特币就是这个矿工挖到的矿。这也是为什么,有的文章说“挖到 1 个 block,就可以得到 XXX 个比特币”,其实它的实际意思是:矿工节点通过不停运算,争取到组装 1 个新 block 并发起全网记账的权利后,可以得到 XXX 个比特币的奖励。讲到这里,你也该明白:其实只要控制了 51% 的矿工节点就可能发起 51% 攻击。


注:可能你会好奇,奖励的比特币怎么打入矿工的账户的呢?其实简单来讲,奖励的比特币也是一笔交易,但这笔特殊的交易没有 inputs,只有 outputs。outputs 里记录的就是矿工节点上登记的公钥地址。所以挖出的比特币只有矿工节点所有者用自己的私钥才可以解锁,这样就实现了对矿工的奖励。


上面介绍的是最典型的几类节点,在比特币网络上还有矿池节点等其它一些节点,就不做过多介绍了。当然上面几类节点的功能完全可以搭建在同一个节点上,这取决于节点搭建者具体想用节点来做什么。


2)比特币的总量


按照比特币系统的设计原理,比特币的发行总数是个定值——2100 万。而比特币的发行,本质就是对“挖矿”的矿工给予的奖励资金。因此,“挖矿”的奖励金额是递减的,每四年会减半一次,会逐渐趋近于 0。



也是因此,比特币是一种不能随意增发的货币。


3)比特币的货币紧缩


货币紧缩不仅体现在上面提到的不能随意增发。想象一下这样的情景,Alice 的拥有 5 个比特币,但有一天,她的电脑完蛋了,硬盘上的数据全部丢失,包括她的私钥,而且她没有备份她的私钥。这意味着什么呢?她的 5 个比特币将永远无法使用,因为用公钥倒推不出私钥,而且其它人也没有她的私钥。这 5 个比特币将永远“死”去。


随着时间的推移,像 Alice 一样的人会越来越多,“死”去的比特币也会越来越多,所以这也将加剧比特币的紧缩。



4)随机生成的私钥


前面讲到,每个用户的私钥是由比特币钱包随机生成的。可能有人会有疑问,这样随机生成的私钥安不安全,会不会我随机生成私钥跟别人的私钥恰好重复了?这个你不用过于担心,因为,比特币私钥是一串很长的文本,理论上比特币私钥的总数是:



这是个什么概念?有人估计过地球上的沙子是 7.5 乘以 10 的 18 次方,然后你想象一下,每粒沙子又是一个地球,这时的沙子总数是 56.25 乘以 10 的 36 次方,仍然远小于比特币私钥的总数。所以在这样一个庞大的地址空间下,私钥重复的概率微乎其微。



5)六个区块的证明


还记得上面提到的,某些特殊的情况下区块链可能分叉,这些情况可能是恶意的双重支付攻击;也有可能是碰巧在同一时点,地球上两个矿工节点同时计算出了小于目标值的 Hash 值,并同时发起了组包记账(这种情况发生的概率极低,但确实曾经发生过)。分叉时,比特币系统会自动选择最长的链条,抛弃短的链条。在这种机制下,越新生成的区块约有可能被抛弃,越早生成的区块越稳定、越安全。



所以一般在比特币网络上,会有一条不成文的约定,就是只有你的交易达成并被装入区块后,后面又生成了 5 个新区块后(加上包含你交易的区块总共 6 个区块),你的交易才是基本安全的。以每 10 分钟生成一个区块的时间来计算,也就是你在交易被确认后 1 个小时左右才能真正确认你的交易是可靠的。


3

总结比特币系统是如何运行的


最后,我们来把比特币系统的运行方式串一遍,也算是一个总结。


1、首先,每个比特币的用户会通过比特币客户端生成一个私钥,并通过私钥生成公钥(公钥与收款地址相关性极强,可以简单理解为收款地址就是公钥),这等于就是这个用户的户头。别人向这个人转账必须输入这个收款地址。



2、用户 Alice 向 Bob 转账时,输入了 Bob 的收款地址,也即是用 Bob 的公钥将这笔比特币锁定了,未来只有 Bob 才能使用这笔比特币。



而用户 Alice 为什么能使用这笔比特币呢?因为,比特币系统可以追溯到上一笔 Charles 给 Alice 转账的交易,在那笔交易里,用户 Charles 用 Alice 的转账地址,将比特币锁定,因此只有 Alice 使用其私钥解锁,才能够使用这笔钱。



所以比特币的绝大部分交易都是由 inputs(来自),outputs(目标)组成。inputs 用来追溯上一笔交易,以便明确转出者是否有权动用这笔钱,outputs 用来进行一次新的加密,加密后只有收款者才能解密并动用这笔钱。



3、交易发生后,将广播全网。很短的时间内,全网所有的节点会接到这笔交易。接到这笔交易后,每个节点会先把交易放入内存,然后对交易进行合法性检验,检验通过后,这笔交易进入有效交易池,等待被装入区块。



4、与此同时,网络上面所有的矿工节点,正在疯狂的计算着谜题。谜题的解题方式就是:将有效交易池里的近千笔交易(TX0, TX1, TX2...),上一个区块的 Hash 值,Nonce 参数组合成一个文本,然后计算这个文本的 Hash 值。通过 Nonce 的不断变化,计算出的 Hash 值也会不断变化。



直到当某一个节点成功计算出小于目标值的 Hash 值,这个节点就解答出了谜题,并有权将计算 Hash 值所使用的信息组装成一个新区块,记录在自己的硬盘上,并发起一次全网记账。




周围的节点在收到广播的消息后,也都记录下这个新区块。




5、由于矿工节点每次都会使用含有上一个区块 Hash 值的文本来计算当前区块的 Hash 值,因此,每一个区块都有上一区块的基因,这使得区块们串成了一个牢不可破的链条。



如果篡改某一区块中的某一交易,那么其后所有的区块数据都无法匹配了。也就形成了区块链不可篡改的特点。



6、比特币系统就这样周而复始的更新着自己的区块链条,不断的进行全网记账,不断的运行下去。



4

结语


我从 2011 年开始接触比特币,还记得 2013 年自己买了一块儿板卡,注册到矿池挖矿的情景(当然好景不长,几个月板卡就烧掉了~)。后来逐渐专注于比特币技术原理。很早就关注这个话题,很早就希望在这里把自己的所学所想与大家一起分享,但工作繁忙一直没有时间起笔,直到 6 月份抽出时间开始写起这篇答案。本来以为很快就能写完,结果断断续续写了两个月。一些概念之前觉得挺明白的,但真要写出来又模糊了,于是又翻了几遍《精通比特币》,巩固了一下自己的知识。所以写这篇答案对我来说也是收获满满。


这篇答案个人认为还是比较容易读懂的,但是篇幅有些长,所以如果你没有耐心一次看完,可以收藏起来慢慢研究。个人认为答案中已经把比特币的一些重要的概念都讲到了,而且也算讲的比较深入。答案中的很多配图来自于一个叫做《How Bitcoin Works Under the Hood》的视频(有一些配图是我结合这个视频的截图及网络图片自己制作出的动画,希望您能喜欢)。这个视频我认为也是快速、全面了解比特币的一个很好的读物,如果您感兴趣也可以看看。在答案中,我根据自己的理解将视频的一些讲解顺序做了调整,并以自己的叙述方式讲解出来,以方便大家更好的理解“比特币系统是如何运行的”。最后,感谢大家阅读了这么长的一篇文章。


我的比特币地址是:1P9hxaoznbwiKJiaLEsfpPEnffyoW9vU37


(完)


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存