Herman

Herman

「BTC 白皮书」学习和总结

BTC 是什么#

在我没有读这本白皮书前,我自然而然的认为,比特币就是一串代码,这一串代码代表一个比特币。但实际上并不是这样的。在整个比特币的系统中,没有一个概念是专门用来指代比特币.

白皮书中提到:

We define an electronic coin as a chain of digital signatures.

我们定义一串数字签名作为一种数字货币.

刚开始读到这里,肯定容易认为,一个比特币等于一段数字签名。随之而来的就是一个巨大的疑惑:那要怎么表示 0.1 个 BTC 呢?

而在后续的「9. Combining and Splitting Value」章节中提到:

Although it would be possible to handle coins individually, it would be unwieldy to make a separate transaction for every cent in a transfer. To allow value to be split and combined, transactions contain multiple inputs and outputs. Normally there will be either a single input from a larger previous transaction or multiple inputs combining smaller amounts, and at most two outputs: one for the payment, and one returning the change, if any, back to the sender.

尽管可以单独处理每个币,但为每一分钱单独进行一次交易将非常不便。为了允许价值的拆分和组合,交易包含多个输入和输出。通常,会有一个来自较大先前交易的单一输入或多个合并较小金额的输入,以及最多两个输出:一个用于支付,另一个用于将找零(如果有的话)返回给发送者。

在整个区块链系统中,存放的只有交易单,比特币只是作为一种计量单位,在交易单作为单位来记录该笔交易转移了多少 BTC. 钱包地址对应拥有的是整个区块链里面的交易单,而非 BTC 本身.

在发起的交易中,交易的过程是怎么样的#

在「2. Transaction」中,原文如下.

We define an electronic coin as a chain of digital signatures. Each owner transfers the coin to the next by digitally signing a hash of the previous transaction and the public key of the next owner and adding these to the end of the coin. A payee can verify the signatures to verify the chain of ownership.

我们将电子币定义为一串数字签名。每个拥有者通过对前一个交易的哈希值和下一个拥有者的公钥进行数字签名,并将这些添加到电子币的末尾,从而将电子币转移给下一个拥有者。收款人可以验证这些签名,以确认所有权链。

按照我们刚刚提到的 BTC 的定义: BTC 只是一种计量单位,真正在区块链上存储的是交易单.

举个例子说明:

在我的钱包地址下面,拥有以下三张交易单:

  1. 往我的地址转入 0.6 BTC.
  2. 往我的地址转入 0.8 BTC.
  3. 往我的地址转入 0.3 BTC.

这三张交易单,说明了我的地址上面,拥有 1.7 个 BTC. 现在,我需要给我的朋友 B 发送 1.5 个 BTC .

首先,这次交易的输入是我所拥有的三张交易单 (因为 1.5 个 BTC, 必须三张交易单才够用).

因此交易发生时,做的第一件事,就是拿我的私钥去尝试匹配这三张交易单后面的数字签名,证明这三个交易单是我的。再开始交易.

其次,前一次交易的哈希指的就是三张交易单对应的三个哈希值.

然后,这一次交易的输出有两张交易单:

  1. 往朋友的地址转入 1.5 BTC
  2. 往我的地址转入 0.2 BTC (找零)

然后,这两张交易单的最后,就会是这样:

  1. 三张交易单的哈希值 + 朋友 B 的 public key 经过计算获得一个数字签名,并把这个数字签名附在 1.5 BTC 交易单的最后面.
  2. 三张交易单的哈希值 + 我自己的 public key 经过计算后获得一个数字签名,并把这个数字签名附在 0.2 BTC 交易单的最后面.

这样就完成了一次转账,把一份交易单的归属权转移到了朋友 B 的下面,另一份找零回到我自己身上。验证归属权也仅需用私钥解密尝试解密验证即可。这是一次 BTC 转账发生的事情.

如何避免发生双重发送?#

什么叫双重发送?我们举一个例子:

现在,我有 10 个 BTC , 我打算个朋友 B 发送 8 个 BTC, 给朋友 C 发送 9 个 BTC. 于是,我按照上面的交易发生的流程,顺利构造出两次交易行为,并同时发起这个交易行为。虽然我们可以轻松的验证 BTC 是否属于自己,但我们没有办法保证,发送的人是否同时还想这些 BTC 发给另一个人.

问题发生的原因在于,B 和 C 随意听信我的话,并且 B 和 C 之间消息不互通,同时也无法弄清楚交易发生的顺序到底是谁前谁后.

现实中,这种问题的解决方案就是引入一个第三方机构, 类似银行这样的角色. B 和 C 只相信这个机构发起的转账,我也只能向这个机构发起转账需求。由于所有转账的行为都必须通过一个中心机构来完成,就不存在什么信息不互通的问题,机构知道我有多少钱,我能转多少,不会任由我随意发起双重发送,同时也能理清楚所有转账发生的前后顺序.

但问题是,引入的第三方机构,需要我们完全去信任它。信任是一个难以监管的行为,在上面的例子中,我们其实无法保证,我跟第三方机构是否有所勾结。即使现实中有很多的程序和手续想让人们设法信任这些第三方机构,但还是那句话:只要整个过程有人的参与,猫腻行为在所难免,时间问题罢了.

BTC 想做的,就是干掉这个第三方机构,由代码设计出一个不需要第三方信任也能保证安全的交易系统.

「Timestamp Server」#

首先第一个举措就是实现一个类似 Timestamp Server 的设计。类似于报纸之类的,记录一个时间和具体的事件,表明所有交易发生的顺序.

而在区块中,BTC 的区块加入了 timestamp, 并用哈希值链接所有的区块.

哈希值是这么计算的:前一个区块的哈希 + 这个区块的数据 = 该区块的哈希。可以认为,每个用于记录交易的区块,靠哈希值链接在一起. 这就是为什么叫做区块链.

在这个计算方式中,哈希的值,依赖前一个哈希的具体值.

一个共识是,哈希算法的输入值即使发生了微小的改变,最后计算出来的值最后也会完全不一样.

那么,假设我们尝试修改第一个区块的时候,整个哈希值会发生巨大的变化。那么第二个区块对应的哈希值,会完全对应不上。为了能够成功篡改第一个区块,你不得不将第二个区块重新计算一遍。依此类推。不论你希望删除,修改历史,都不得不将所有区块的数据都更新一遍.

每次新增一个区块,都会增强前面所有区块的不可修改性,保证时间的顺序性.

「Proof-of-Work」#

BTC 中的工作量证明机制。每个矿工都在为自己有权利写入新区块上付出相当的算力努力。给出工作量证明之后,节点 (矿工) 才有权利往新区块写内容.

如何提供工作量证明呢?BTC 是这么设计的:

每个区块由以下部分组成:

  • 上一个区块的哈希值 (prev hash)
  • 当前区块的所有交易数据 (实际中应该存放的是 Merkle Root)
  • 时间戳
  • 难度目标 (决定工作量证明中哈希值需要多少个前导 0)
  • 随机数 (nonce)

在这里面,矿工唯一不知道的内容是「随机数 (nonce)」. 而这个 nonce 值就是所谓的「工作量证明」.

在「Proof-of-Work」中,矿工们需要完成这样一道数学题:我们已知除了随机数以外的所有内容计算出来的哈希值,请计算出当 nonce 为多少时,哈希值的前面 n 位为 0, 剩下的数字都为之前的哈希值?其中,n 具体有多少位,由难度目标来决定.

至于难度目标是怎么生成的。这个我翻找了下资料,暂时没有弄明白。只知道这个难度目标是根据网络当前的生成区块难度动态调整的.

当 nonce 的值被计算机计算出来,这个就可以作为节点的「工作量证明」, 证明节点有权利写入新区块,写入区块后向所有节点广播即可。虽然计算出 nonce 的值非常困难,但是验算这个值是否正确却很简单,其他节点只需要代入后计算是否和预期相等即可验证.

计算出 nonce 对与计算机来说不是一件简单的事情,它需要相当多算力才能把结果算出来。因此,结合前面的「Timestamp Server」, 如果有人希望修改区块,那么这个 nonce 的计算是无法回避的.

如果希望修改区块的历史,你不得不准备好相当的计算机算力,将所有涉及的区块的 nonce 全部计算出来。随着时间推移,难度目标会越来越大,后续计算的难度会越来越高,区块越多,历史就越难被篡改.

「Network」#

  1. New transactions are broadcast to all nodes.

  2. Each node collects new transactions into a block.

  3. Each node works on finding a difficult proof-of-work for its block.

  4. When a node finds a proof-of-work, it broadcasts the block to all nodes.

  5. Nodes accept the block only if all transactions in it are valid and not already spent.

  6. Nodes express their acceptance of the block by working on creating the next block in the chain, using the hash of the accepted block as the previous hash.

  7. 新的交易被广播到所有节点。

  8. 每个节点将新的交易收集到一个区块中。

  9. 每个节点尝试为其区块找到一个困难的工作量证明。

  10. 当某个节点找到一个工作量证明时,它将该区块广播到所有节点。

  11. 节点只有在区块中的所有交易都有效且未被花费的情况下才会接受该区块。

  12. 节点通过使用已接受区块的哈希作为前一个哈希来创建下一个区块,从而表示它们对该区块的接受。

Nodes always consider the longest chain to be the correct one and will keep working on extending it. If two nodes broadcast different versions of the next block simultaneously, some nodes may receive one or the other first. In that case, they work on the first one they received, but save the other branch in case it becomes longer. The tie will be broken when the next proof- of-work is found and one branch becomes longer; the nodes that were working on the other branch will then switch to the longer one.

节点总是认为最长的链是正确的,并会继续努力扩展它。如果两个节点同时广播不同版本的下一个区块,一些节点可能会先收到其中一个。在这种情况下,它们会先处理它们收到的第一个版本,但会保存另一个分支以防它变得更长。当找到下一个工作量证明且一个分支变得更长时,平局将被打破;正在处理另一个分支的节点将切换到更长的那个分支。

结合以上几点。双重发送的问题被解决.

  • 如果我尝试同时发起两个交易企图完成双重发送,工作量证明 + 时间戳服务的设计可以让交易形成一个时间顺序,并广播到所有的节点。顺序保证了双重发送无法完成.
  • 如果我尝试从不同的地理位置完成双重发送,工作量证明的难度会让节点很难同时完成两个交易.
  • 即使真的让两个分隔两地的节点同时将这两个交易写入了区块. BTC 也会发生分叉,直到分叉较长的取代掉较短的。能保证两个交易只有一个能成功.

总结#

双重支付问题是指同一笔比特币被用于两次支付。比特币通过工作量证明和最长链原则来解决这一问题。当新的交易被广播到网络中,矿工将其打包到区块中,通过工作量证明找到符合难度要求的哈希值,并将区块添加到区块链中。

如果两个交易试图花费同一 UTXO,只有一个交易会被首先包含在区块中,而另一个交易由于 UTXO 已经被花费而无效。最长链原则确保了整个网络达成共识,防止双重支付。

Merkle Tree#

前面提到过这个 Merkle Tree. 如果需要节省磁盘空间,节点的区块存储可以不存储具体的数据。仅需要将区块里面所有的交易的哈希以 Mertle Tree 的形式,两两算出一个根 hash, 就不再需要存储数据,用 root hash 即可验证数据是否一致.

即使我们想验证区块上的某个交易,我们只需要拿着这个区块头去找网络节点上其他存了数据的节点,在他的数据上找到最长链节点对应的数据即可验证自己的交易.

第一个 BTC 从哪里来?#

有一个区块最特殊,他的哈希没有被任何一个区块链接,那就是创世区块。首个 BTC 就诞生在这个创世区块中,有 50 BTC.

之前提到过「Proof-of-Work」, 每个矿工节点在竭尽全力计算,求的写入区块的权利.

首先,求得 PoW 的矿工,会获得区块奖励。一开始一个区块奖励 50 BTC, 后面每四年减半。直到挖出 2100w BTC 终止。这是挖矿的由来,也是 BTC 主要的来源.

比特币的区块奖励大约每 210,000 个区块(约每四年)减半一次。这种设计是为了控制比特币的总供应量。

  • 第一次减半(2012 年):奖励从 50 个比特币减少到 25 个比特币。
  • 第二次减半(2016 年):奖励从 25 个比特币减少到 12.5 个比特币。
  • 第三次减半(2020 年):奖励从 12.5 个比特币减少到 6.25 个比特币。
  • 未来的减半将继续,直到所有 2100 万个比特币被挖出为止。

其次,求得了 PoW 的矿工,自然有权利收取每次交易的 gas. 矿工主要的收入来源就是挖矿和 gas .

关于钱包#

实际上,钱包里面存的不是比特币,而是比特币的交易单(UTXO)。如果你想知道你的地址里面有多少钱,实际上你需要遍历整个区块链,将所有跟自己有关的 UTXO 找到,再把数据加总。

听起来这个操作挺慢的,但实际操作中,大部分钱包软件都利用内存和索引做了一些优化,使查询速度更快。具体实现方式可以包括 Bloom 过滤器、地址索引等技术。

一个区块实际上不止一个交易?#

应该是的.

交易不是立刻被写入区块的,它们收到并被广播以后,首先会放到内存池中(mempool)。

然后矿工会从内存池中选择交易进行打包,计算哈希,然后开始计算 nonce 值以获得工作量证明(Proof-of-Work)。

如果矿工如愿以偿地找到了 nonce 值,这些交易才会被确认并写入区块。

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.