0.5 比特币?看这篇就够了(下):记录即价值

前面两篇文章白皮哥已经为大家梳理了:

比特币网络的基本组成:比特币?看这篇就够了!(上):节点即细胞
比特币相关算法:比特币?看这篇就够了!(中):算法即魔法

其实前两篇文章偏重于碎片化的知识,很多朋友读完之后感觉上基本理解了,哦,是这么回事,但是然后呢?矿工、钱包、全节点客户端是怎样在比特币系统中发挥作用的?椭圆曲线算法、哈希函数在比特币运行过程中到底是怎样发挥作用的?

下面,白皮哥就用几个故事来串联这些知识,为大家进一步讲述比特币是怎样运转的。(看到陌生的概念可以去上篇和中篇查找)

1. 进入网络(以核心客户端为例,其他类型节点类似)

A听说比特币挖矿很来钱,就买了一台笔记本准备挖矿,又从 https://bitcoin.org/zh_CN/download 下载了比特币核心客户端准备挖矿。还记得这张图吗?

比特币核心客户端

他按照说明启动了比特币核心程序,此时,A的笔记本就进入了比特币网络,成为了一个节点。此时,节点A开始在网络里寻找另一个比特币节点(通过网络路由),很快,它找到一个节点B,并且比特币核心的版本是兼容的。A就让这个在网络里比它资深的B给它介绍自己相连的节点地址。这样,通过一层层引荐,A就认识了很多节点,当A有消息需要广播的时候,它就会告诉认识的节点们。但A也不是那么喜新厌旧,它会记住第一个连接的节点B,当A重启之后,会直接去找B,这样就可以完成网络关系的获取。

因为比特币网络里的节点随时会退出,网络里的每一个节点都必须接受这个事实,因此没有消息广播的时候,A也会定时给其他节点发信,如果某个节点90分钟都没有反应,A就会认为它挂了,再去寻找新的节点以保持连接的节点数量。当然,网络里随时也会有新人来,A也会向找到它的新节点介绍它自己的通讯录,帮助新节点启动。

这样,比特币网络中的节点同时连接到多个节点,构成了一个网状结构,任何节点的退出和进入都不会影响整个比特币网络的稳定,它的意义请看这篇文章:区块链是劳动人民对银行家的宣战

找到朋友们之后,A作为一个比特币核心客户端,属于全节点客户端的一种,需要构建一份完整的区块链,但之前从网上下的客户端软件里只有第一个区块(创世区块),因此A需要同步链上后面所有的区块。其实在任何两个节点见面时,他们都会互相比较自己的区块链长度(区块高度)。

既然A只有一个区块,肯定是不如网络里的这些老资格们的,所以B会把它前500个区块的哈希发给A,A验证(区块结构请见下面)后将向它所有的连接节点请求区块内容,一个区块一个区块地构建整个区块链,一直到追上最新的区块为止。当区块链构建完成,A就是一个真正的全节点客户端了,当然,如果A下线过,当它再上线的时候它还是要再像前面讲的一样“补一次课”。

2. 付款

C前几天从矿工E那买了1个比特币,她突然发现楼下咖啡馆接受比特币支付了,所以她准备去试试。C来到咖啡馆,通过手机里的比特币钱包支付了0.005个比特币,交易里咖啡馆的账户是D。C手机和D的收款电脑里的比特币钱包一般是SPV钱包,因为大多数人不会本地保存一份几百G的完整区块链。在付款时,C新建并签名了一条交易,然后向比特币网络广播:

交易2

而图中交易1则是区块链上C从矿工E那买比特币这笔交易:

交易1

其中C的签名证明了这笔交易是交易1的第一个输出的所有者(C)发出的,其他人无法冒充,细节请见中篇:比特币?看这篇就够了!(中):算法即魔法

3. 挖矿

A加入比特币网络后终于完成了区块链的同步,假设目前总共有1001个区块,其中上面的交易1就在第999个区块里,现在A开始挖矿,它收到了上面C向网络里发的买咖啡的交易,验证:

交易1的第一个输出是交易2的输入(C),

交易1输出(1个)大于交易2的输出(0.005+0.994),

锁定脚本可被交易2解锁,因此它是有效交易,加入待打包的交易池。注意交易2的输出(0.005+0.994)小于其输入(1),这个差值就是手续费,手续费越高矿工会越早把这笔交易从待打包的池子提出来打包。

这时第1002个区块的争夺刚刚结束,A没有成功,因此,它接受了网络同步过来的第1002个区块,开始自己打包1003区块:其中第一个交易是coinbase交易,输入为空,输出为自己,数量是12.5个:

coinbase交易

这是对矿工的奖励。然后A又打包了4000个交易(不能无限打包,区块大小要小于1M),其中就有上面的交易2。这些交易中的手续费都归A所有。然后,A需要为这些打包好的交易加一个区块头,形成一个完整区块:

区块结构

(绿色为区块头,蓝色为区块内容)

区块头中包括链上前一个区块头的Hash、打包时间、挖矿难度(用于控制多久挖出一个区块)、Nonce值(矿工自主变换,以使区块头Hash值小于难度设置的Hash值)、Merkle根(用于快速验证某个交易,比如前面的交易1是否在区块中)。细节同样请见中篇:比特币?看这篇就够了!(中):算法即魔法

总之,假设目前系统挖矿难度是要求区块头的Hash值前6位要是0。A不断修改区块头的nonce值,计算每个区块头的Hash,最终算出了区块头的Hash值为0000002a7bb274121cbd…. 符合了难度要求,这时A还没有收到广播来的区块(如果收到了则挖矿失败,放弃,重新打包1004区块),因此它赶快把这个包含有交易2区块广播到比特币网络中。

比特币网络中的其他矿工节点(比如B),收到了A发来的1003区块,验算(Hash算法只能遍历,但是知道输入易于验算输出是否正确)发现确实区块头的Hash符合难度要求,就把1003区块加入自己的区块链,放弃他们自己的打包,重新打包开挖1004区块。并把A的1003区块广播给其他节点。

4. 验证

咖啡馆D的钱包应用是一个SPV钱包,它电脑上没有完整区块链,对于比特币网络中其他人的交易也不感兴趣,它只想知道和自己账户D有关的输入输出。当C付款0.005个比特币给D(交易2)之后,经过A的挖矿,交易2已经上了区块链。D就会收到比特币网络的一条Merkleblock消息,包含交易2所在区块(1003区块)的区块头和一条连接交易2和区块头中Merkle根的Merkle路径。此外D还会收到交易2的信息。这时候,咖啡馆D就可以根据交易2沿着Merkle路径去寻找Merkle根,如果算出的Merkle根和Merkleblock消息中的根一致,说明交易2在区块1003里。然后,因为1003区块头中有上一个区块的Hash值,D很容易就可以向比特币网络求证1003区块是不是已经在链上了。所以,验证的过程证明了:交易2在区块1003上,区块1003在区块链上,这时咖啡馆D就可以认为交易2生效,0.005个比特币到账,可以给C咖啡了。

5. 小问题

上面的一切非常完美,但是有一个小问题。矿工A打包好区块1003(如下图正三角)向B和其他人发的时候,万一千里之外的另一个矿工F也同时挖出了一个区块1003(如下图倒三角)向网络广播怎么办(虽然概率不大)?现实中网络传输是有延迟的:

同时挖出

这时候A和F分别告诉他们的邻居们他们的新块,而他们的邻居也都认可加入了链。这时全网就分成了两个阵营,三角派和倒三角派,这种情况就叫分叉

分叉

当某个阵营的节点收到对面节点的新块时,他们不会丢弃,而是默默存下来。但还是以原有的为准。等下一个区块1004被挖出来时:

新区块

因为挖出1004块的人是三角派,所以当这个1004块传递到倒三角派时,倒三角派会因为有这个绿色的菱形的链更长而叛变到三角派的链。当菱形传播到全网,则全网的认识就又统一了:

分叉结束

这就解决了同时挖出不一样区块的问题,也就是解决了一笔钱花两次(类似你和你爸同时在两个ATM机取钱)的问题。那爱抬杠的你就要说了,如果第二个区块(区块1004)也是同时挖出来两个不一样的怎么办?当然是等区块1005了。实际上,1个区块的分叉几乎每天都发生,2个区块的分叉好几周才发生一次,目前最多的一次分叉为5个区块的分叉:2015年7月4日,因为区块版本升级(2至3),导致倒三角派(版本2)不接受三角派(版本3)的新块,一定要等自己派系的新块挖出才接受,这样就形成了5区块分叉。最终通过代码升级解决了上面的问题才消灭了分叉。

分叉会造成交易回退的问题,比如假设C买咖啡的交易2是被矿工F挖出的,且存在于倒三角那个区块里,但是倒三角的区块最终因为分叉被抛弃了,这时候D看到钱到账就给了咖啡,过了一段时间分叉消失钱就又没了。所以一般来说,钱包应用会等待倒三角区块上面新增6-8个区块之后再确认到账,因为有6-8个区块是基于倒三角区块时,基本已经不存在回退的可能了(如果存在回退,对比特币系统将会是一个大事件)。

好了,大家搞清楚区块链的运作流程了吗?本篇着重介绍了实现交易这一部分,可以看到比特币的优越性在于,每一笔交易都是互相链接的,如果我要花一笔钱(在交易中添加“输入”),我必须要提供一笔交易的“输出”,且证明这笔交易的输出是给我的。而交易也就是所谓的“帐”。而比特币中也没有“余额”的概念,大家在比特币钱包中看到的所谓的钱包余额,其实是钱包筛选出交易“输出”为本钱包地址的交易,其中没有被列为任何交易输入的(没有被花过的)就称为UTXO(unspent transaction outputs),未花费输出,他们的和就是余额。

不同于目前的银行系统,区块链系统把“账”和“资金”合二为一了,不存在记账、清算、结算的过程,也不存在账不平,因为这本账绝对可靠,账户上的钱就应该根据账上的交易来计算。

「 因此,区块链上的每一笔记录就是价值,每一笔交易就是资产。」

推荐阅读更多精彩内容