理解区块链和比特币(一)

区块链是相当热门的一项技术创新。媒体,投资人和庄家把这项技术推到了一个极高的位置。区块链被认为在金融、征信、贸易、资产管理等众多领域都拥有广泛的应用前景。
区块链到底是什么,能解决什么样问题?如何从技术实现的角度去理解区块链?

本质

从Bitcoin最初发表的论文看,他所设计的是一套P2P环境下的数字货币系统,实现了在不依赖金融机构的情况下进行货币交易.
在实现上, Bitcoin主要做了两件事情:

1. 引入了一套基于密码学的电子交易记账方式。
2. 为了解决这种交易记账方式在分布式P2P网络环境下面临的一些列问题,引入了区块链和工作量证明机制。

实际上,Bitcoin描绘了这样的一个场景:

存在一个总账本,它记录了所有用户之间的交易信息;
每一条记录都是真实可靠的,经过验证的,并且得到了所有人的认可。
每个用户都有一本总帐本的复本,都有权力去查看交易记录。

在这种场景下,在线交易的双方可以不再需要金融机构的介入,数字资产能够安全可靠的实现交付。为了达到这样的目的,比特币尝试了一套非常特殊的设计。

基于密码学的记账方式

直观上,比特币网络需要一个总账本(Ledger),用来记载的用户之间的交易(Transaction)。交易这个行为可以被简化成用户X给了用户Y一笔钱S,那么在账本上这个最简单的交易信息可以被记录为:[用户X 支付 金额S 给用户Y]
但是这样并不够,我们还需要知道:

1.    用户X完成付款资金来源以及有没有足够的钱来完成这笔支付;
2.    如何验证这笔交易是用户X发起的;

用户X拿什么来支付?

Bitcoin规定,每一笔交易都要依赖前一笔或几笔未花费的交易(UTXO,Unspent Transaction Output),这和支票有些相似。简单的说(不考虑找零的情况),用户X曾经收到过一笔来其他人的转账,之后他才可以用这笔转账来给别人支付。例如之前存在一笔交易[用户Z 支付 金额S 给 用户X],交易编号为001,那么当前的交易可以是 [用户X 使用 [交易001的收入] 支付 金额S 给 用户Y],交易编号为002。类似的,用户Y收到这笔交易后,可以继续使用交易002进行其他支付。可以看到,这里的交易信息结构将会是一个链式结构(单向的树状)。

如何对交易进行签名和验证。

对于一个比特币用户,他需要拿到一套非对称密钥。用户的私钥需要用户自己保存好,不能泄露。用户的公钥可以作为接受转账的地址(实际上,公钥到地址的转换还需要经过一些列的哈希变换)。
要发起一个交易,发起者用户X需要填写如下内容:

*    这笔支付的资金来源,也就是之前收到的“支票”ID。
*    用户X使用他的私钥对这笔交易内容的的数字签名。(实际是对[交易内容+前一个交易]的hash值签名)
*    接收方(用户Y)的公钥。

此时,我们记载一条账目到总账本的流程可以如下描述:

1. 用户X发起一个交易请求:[用户X 使用 [一笔存在的转账] 支付 金额S 给用户Y]+[用户X对这笔交易的数字签名]。
2. 在记录到账本上之前,需要验证这样几个事情:
    a. 这笔交易的数字签名是否真实有效。(用上一笔交易中的公钥解密签名,计算[交易内容+前一个交易]的hash值,判断这两个值是否相等)
    b. 查阅账本,查看资金来源未被用户X使用过。
    c. 检查交易是否合法:资金来源的支票的金额大于等于要支付金额。
3. 如果上述检查通过,所有人都同意交易合法,那么就在总账本上记下来。

上述流程保证了交易信息的真实可靠,无法伪造,也定义出了交易信息的格式。

Note* 这里尽量避免使用余额这个概念,因为这个账本上是不会记账某个用户的余额信息的,只记载用户之间交易信息。

如何在P2P环境下维护一个总账本

所谓的总帐本是不存在的,比特币网络实际上是让所有的节点手里都有一本内容一致的账本。也就是说任何一笔新的交易产生,每个人手里的账本都要增加这条交易记录。
此时,在这样一个P2P环境下面,会存在如下的问题:

1.    如何同步全网交易记录。例如,某用户离线了一天,这一天之内的交易该用户并没有收到,怎么去找这些记录?
2.    如何保证节点所同步到的交易记录是未经篡改的?
3.    如果保证双重支付(double spending)的问题不会发生?例如,如何阻止用户X发起两笔交易把同一张10块钱既支付给了Y,又支付给了Z。

实际上,这些问题与分布式数据库的一致性问题非常相似。分布式数据库往往是通过一个全网同步的高精度时间服务器给交易加时间戳方法来解决这些问题。但在P2P的结构下,这种基于高精度时间戳方案不可行。比特币网络在这个时候引入区块链和工作量证明(Proof of work)来解决这些问题。

区块

区块(Block),就是一堆交易的集合,类似与数据库中需要提交(commit)的一个事务(transaction)。当比特币网络中产生了一定数量的交易,经过验证这些交易都是合法有效的,那么就把这些交易信息就可以打包成一个区块,并且在这个区块的头部记录下前一个区块的信息(哈希值),再把这个区块放到上一个区块的后面。如此往复,所有的交易都被打包存储在一个一个的链式的区块中。这个由区块组成的链式结构就是全网共同所有的总账本。所有的节点只要同步好这些区块,就能获得这个账本上所有的交易信息,这解决了问题1.

此时,又有了这样两个问题:

4.    打包区块的事情显然每个节点都可以做,同一时间可能会有大量的区块被提交,节点到底认可哪个块,并加入到手里的区块链中?
5.    打包区块这么“无聊”的事情,节点凭什么愿意做?

工作量证明

对于问题4,比特币网络采取了一个“延缓”打包的策略。既然大家都会打包,那我就不让你们轻松的把包打出来,在一定的时间内,保证全网只有一个区块被打包出来。
比特币网络增加了一个这样的要求:

SHA256(打包好的所有交易信息 + 节点找到的一个数字)的哈希结果的前n位必须是0(实现上要求这个哈希值小于某个目标值)。

就是说,节点光记录好交易的信息是不够的,还要找到一个特定的数字nonce,让(交易记录集合+nonce)的哈希结果的前n位为0(n常见为16)。找这个nonce的过程,被称为挖矿,做这个事情的节点就是矿工。这就有意思了,因为哈希结果是不可预知的,没有捷径可走,所以矿工只能一个数字一个数字的去试,直到哈希出来的结果符合要求,猜中这个nonce的概率等价于“抛硬币连续n次是正面”的概率。这个nonce被称作工作量证明。加上这个极其变态和无聊的规则之后,全网所有的矿工往往只有一个人能在十分钟之内找到一个nonce。此时,当一个矿工节点把一个新区块广播出去的时候,其他节点往往还在苦苦寻找nonce。其他人一旦收到这个区块,立刻停下手里的工作,验证一下nonce是否正确,区块内的交易是否合法。若验证通过,就把这个区块加到自己维护的主链中,然后继续打包那些未被区块记录的交易;如果未能通过验证,则抛弃这个块,继续刚刚的工作。

Fork

虽然这个要求非常难以满足,但是还是会存在两个矿工差不多同时广播出两个合法的区情况块。既然都合法,节点就继续在先收到的区块后面继续工作,并保留另一个合法的区块。然后等等看,过一会肯定还会收到新的区块,那时再看看这个新的区块的头部包含这两个中的哪一个区块的哈希,包含哪个区块,哪个块就作为有效块,舍弃另外一个,如此下去。这套机制保证了在一定的时间内全网最长的主链会收敛到一致的状态。(其他特殊状况这里暂不讨论)

The Magic

神奇的是,这个奇葩的规则和区块链结合在一起也一并解决了问题2和问题3,因为:

1.    如果有人要篡改交易信息,意味着:
    i.    他要控制大量的节点(>50%),才能保证修改结果被剩下的人接受。
    ii.    修改或者伪造一条交易,意味其后所有区块中包含的nonce值都要重新计算,这个计算量大到不可能。
2.    全网主链状态唯一,账本信息一致,因此double spending这种非法交易肯定被拒绝。

这个诡异的计算“游戏”还能控制难度:如果越来越多的算力加入计算,只要增加哈希结果最前面0的个数要求(目标哈希值越小,越难),就可以指数级增加难度。比特币网络会自动根据出块的平均速度自动调整难度,保证平均只有10分钟之内只出一个块。

比特币的诞生

对于问题5,比特币网络决定给成功打包并被全网认可的矿工一定的比特币作为奖励。此时比特币就凭空诞生了!如果去检查每一笔交易的支付来源,不断的追溯源头,一定是落在了某个挖矿奖励上(Coinbase)。比特币网络又规定,初始挖矿的奖励是每打包出一个区块给50比特币,全网每生产出21000个区块,奖励减半。奖励减半机制是得能够用于奖励矿工的比特币总量收敛在2100万个(差一点点)。
没有奖励之后还会有人挖矿吗?会,慢慢的,一个区块中所有交易的转账手续费会成为矿工的主要收入。

总结起来

比特币网络首先引入了一套加密的电子交易记账方式。为了解决这种交易记账方式在分布式网络下面临的问题,引入了区块链和工作量证明机制。

Reference: