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 值,這些交易才會被確認並寫入區塊。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。