簡(jiǎn)介
比特幣本身是一種分布式的,去中心化的數(shù)字貨幣。我們可以在大的層面上分為兩部分:協(xié)議和實(shí)現(xiàn)。
協(xié)議是比特幣中最重要的部分,按照官方的guide,大體上分為,Block Chain 區(qū)塊鏈,Transactions 交易,Contracts 電子合約,Wallets 錢包,P2P Network P2P網(wǎng)絡(luò)等幾大塊。
而Payment Processing 交易流程, Operating Modes 操作模式, Mining 挖礦,放在后面來介紹。我認(rèn)為這些部分緊密的與實(shí)現(xiàn)相關(guān),而且相關(guān)協(xié)議的內(nèi)容,都會(huì)在前面的內(nèi)容里面提及。
下面我們來介紹第一部分,Block Chain 區(qū)塊鏈。
Block Chain 區(qū)塊鏈
區(qū)塊鏈為比特幣提供了一個(gè)公開的記帳本,這個(gè)記帳本記錄了交易的發(fā)生順序和發(fā)生的時(shí)間。使用這個(gè)記帳本的目的是防止出現(xiàn)重復(fù)消費(fèi)(一筆錢花兩次),以及對(duì)已經(jīng)完成的交易記錄進(jìn)行修改(撤回已經(jīng)交易完成的資金)。
這里需要提及一個(gè)概念,“全功能節(jié)點(diǎn)”(full node),具體關(guān)于全功能節(jié)點(diǎn)的介紹會(huì)在operating mode中具體說明。所謂全功能節(jié)點(diǎn),就是完整實(shí)現(xiàn)了比特幣相關(guān)協(xié)議的節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)會(huì)獨(dú)立存儲(chǔ)一條被該節(jié)點(diǎn)認(rèn)可的區(qū)塊鏈(這里說的認(rèn)可,也是比特幣協(xié)議中的一個(gè)重要組成,如何驗(yàn)證一條區(qū)塊鏈?zhǔn)呛戏ǖ模覀円矔?huì)在后文提及)。
區(qū)塊鏈實(shí)際上由兩部分組成:區(qū)塊 Block, 鏈 Chain。
當(dāng)多個(gè)節(jié)點(diǎn)所認(rèn)可的區(qū)塊鏈,擁有一模一樣的區(qū)塊時(shí),我們可以說這些節(jié)點(diǎn)是“一致的”。這些節(jié)點(diǎn)認(rèn)可區(qū)塊鏈的方法(區(qū)塊鏈驗(yàn)證規(guī)則 validation rules)被稱為一致性規(guī)則。在后續(xù)的章節(jié)里,我們會(huì)描述很多比特幣所使用的一致性規(guī)則。

如上圖所示,圖中的箭頭就是鏈。而區(qū)塊則分為了兩個(gè)部分,Block Header 區(qū)塊頭,和Block Transactions 區(qū)塊的交易記錄。在區(qū)塊頭中,我們看到了“Merkle Root”這個(gè)詞,這是一個(gè)在鑒權(quán)方面應(yīng)用較為廣泛的樹結(jié)構(gòu)。這里有一篇介紹Merkle Tree的文章,推薦看一下。
在上圖中可以看到,Chain的建立實(shí)際上就是構(gòu)建一個(gè)Hash值,后一個(gè)Block Header存儲(chǔ)前一個(gè)Block header的Hash值。這樣,我們?cè)谶壿媽用?,我們只要以每個(gè)Block header的Hash值作為唯一標(biāo)識(shí),我們就有能力構(gòu)建一個(gè)鏈狀結(jié)構(gòu)了。唯一的問題就是每次都需要計(jì)算每個(gè)Block header的hash值,效率太低。關(guān)于這個(gè)問題,我們可以稍后看具體實(shí)現(xiàn),來了解比特幣是如何解決這個(gè)問題的。
在上圖中,我們還有一個(gè)問題是Block為什么被分為了Block header和Block Transcations兩個(gè)部分。這其實(shí)是一個(gè)基于性能和方便性的考慮,交易是可能持續(xù)變化增加的,這樣Block本身就會(huì)不斷變化,并且所占磁盤空間也會(huì)持續(xù)增長(zhǎng)。如果我們單純的以鑒定交易是否合法為目的,我們可以只存儲(chǔ)Block Header,也就是使用所謂的SPV來進(jìn)行校驗(yàn),在這種情況下,磁盤消耗會(huì)大幅降低。
下面我們來單獨(dú)說說交易,交易也是彼此被鏈接到一起的。比特幣錢包給大眾一個(gè)印象,就是錢是從一個(gè)錢包發(fā)送到另外一個(gè)錢包的。而實(shí)際上并非如此,比特幣是從一筆交易移動(dòng)到另外一筆交易的。(本質(zhì)上,比特幣從未進(jìn)入過任何一個(gè)錢包。我們?cè)诒忍貛派蠈懮弦粋€(gè)名字,誰就擁有了這枚比特幣的使用權(quán)。我們進(jìn)行交易,實(shí)際上就是不停的在Block Transcations里面寫收款人的名字)。每一筆交易都是使用相關(guān)的上一筆或者幾筆交易的輸出,所以,每一筆交易的輸入,都是之前交易的輸出。

(對(duì)于 Triple-Entry Bookkeeping 翻譯為三式記賬法是否合理我是存有疑慮的,因?yàn)樵谏蠄D中,沒有能體現(xiàn)負(fù)債的概念,上圖看起來更像一個(gè)交易明細(xì)。)
如上圖所示,一筆交易可以產(chǎn)生多個(gè)輸出,即一筆交易同時(shí)向多個(gè)地址發(fā)起輸出。(我們?cè)谶@張100塊錢的紙幣上寫,給張三40,給李四50)但是一個(gè)輸出,只能被使用一次。想要被使用兩次的輸出會(huì)被拒絕,因?yàn)槲覀儾辉试S同一筆錢被花費(fèi)兩次。
(備注:Transaction 在很多文檔中被簡(jiǎn)寫為TX)
因?yàn)槊恳粋€(gè)輸出都只能被使用一次,所以我們可以統(tǒng)計(jì)區(qū)塊鏈中全部未使用的輸出,記作UTXO(unspent transaction output)。一個(gè)合法的交易,它的輸入必須是一個(gè)UTXO。
我們暫時(shí)忽略幣基交易,如果一個(gè)交易的輸出大于輸入,這筆交易會(huì)被拒絕。但是如果輸入大于輸出,那么輸入和輸出之間的差額,會(huì)被作為交易費(fèi)支付給發(fā)現(xiàn)這個(gè)Block的礦工。如上圖所示,每一次交易,輸入和輸出之間總有10k聰?shù)牟钪?,這個(gè)差值就是交給礦工的交易手續(xù)費(fèi)。
Block Chain實(shí)現(xiàn)細(xì)節(jié)
Block Headers 區(qū)塊頭
區(qū)塊頭被序列化為80字節(jié)的二進(jìn)制格式。對(duì)區(qū)塊頭執(zhí)行哈希函數(shù),得到的哈希值會(huì)參與到比特幣的工作證明算法中。因此,區(qū)塊頭的序列化協(xié)議是一致性規(guī)則中的一部分。
| 字節(jié)數(shù) | 名稱 | 數(shù)據(jù)類型 | 描述 |
|---|---|---|---|
| 4 | 版本號(hào) | int32_t | 區(qū)塊版本號(hào)指明區(qū)塊需要遵守的驗(yàn)證規(guī)則,具體可以查看區(qū)塊版本號(hào)的相關(guān)章節(jié) |
| 32 | 前一個(gè)區(qū)塊頭的哈希值 | char[32] | 對(duì)于前一個(gè)區(qū)塊頭,使用sha256(sha256())進(jìn)行運(yùn)算,并以內(nèi)部字節(jié)順序進(jìn)行排列(哈希值按照展示為string的順序進(jìn)行排序) |
| 32 | merkle root哈希值 | char[32] | 根據(jù)區(qū)塊中全部交易構(gòu)建的merkle root,對(duì)該root進(jìn)行sha256(sha(256()))運(yùn)算,取值以內(nèi)部字節(jié)順序存儲(chǔ) |
| 4 | 時(shí)間戳 | uint32_t | 礦工開始執(zhí)行哈希的unix時(shí)間戳。該時(shí)間戳必須嚴(yán)格大于前11個(gè)區(qū)塊的中位數(shù)時(shí)間。全功能節(jié)點(diǎn)將會(huì)拒絕晚于當(dāng)前時(shí)間兩小時(shí)的區(qū)塊。 |
| 4 | nBits | uint32_t | 經(jīng)過編碼的區(qū)塊頭哈希目標(biāo)閾值。注意和挖礦難度進(jìn)行區(qū)分。 |
| 4 | nonce | uint32_t | 一個(gè)可以由礦工定義的任意數(shù)字,目的是使得區(qū)塊頭的哈希值不高于目標(biāo)閾值。如果32位全部經(jīng)過了測(cè)試而沒有符合目標(biāo)閾值的哈希,我們可以更新時(shí)間戳,或者更新coinbase transaction以及merkle root。 |
哈希值全部采用內(nèi)部字節(jié)順序,其他值均采用小字節(jié)序。
02000000 ........................... 版本號(hào): 2
b6ff0b1b1680a2862a30ca44d346d9e8
910d334beb48ca0c0000000000000000 ...前一個(gè)區(qū)塊頭的哈希值
9d10aa52ee949386ca9385695f04ede2
70dda20810decd12bc9b048aaab31471 ... Merkle root哈希值
24d95a54 ........................... unix時(shí)間戳: 1415239972
30c31b18 ........................... Target: 0x1bc330 * 256**(0x18-3)
fe9f0864 ........................... Nonce
Block Version 區(qū)塊版本號(hào)
- V1 創(chuàng)世塊首次使用(2009年1月)
- V2 Bitcoin Core 0.7.0 首次通過軟分叉的方式使用(2012年9月),V2版本需要提在coinbase中提供區(qū)塊高度這一參數(shù),在BIP34中詳細(xì)說了該版本。2013年3月,V2版本的區(qū)塊開始拒絕區(qū)塊高度在224412之后的不能提供區(qū)塊高度的區(qū)塊,并于三周后,(區(qū)塊高度為227930)拒絕使用V1版本的區(qū)塊。
- V3 Bitcoin Core 0.10.0 首次通過軟分叉的方式使用(2015年2月)。當(dāng)分叉達(dá)到執(zhí)行點(diǎn)時(shí)(2015年9月),V3要求區(qū)塊必須嚴(yán)格以BIP66中描述的DER編碼方式來編碼全部的ECDSA簽名。不使用DER編碼方式的交易,在Bitcoin Core 0.8.0中就被標(biāo)記為非標(biāo)準(zhǔn)的了(2012年2月)
- V4 Bitcoin Core 0.11.2 在2015年12月以軟分叉的形式引入。該標(biāo)準(zhǔn)詳盡描述中BIP65中。V4支持了新的opcode,OP_CHECKLOCKTIMEVERIFY
V2,V3,V4采用的升級(jí)方法為 IsSuperMajority(),該方法的目標(biāo)就是管理通過軟分叉發(fā)生的修改。關(guān)于該方法的描述可以參見BIP 34.
當(dāng)這篇文章正在寫作的時(shí)候,一種更新的,稱之為“version bits”的方法正在設(shè)計(jì)中。該方法的目標(biāo)是以全新的方式來管理軟分叉,然而,我們并不確定,V4會(huì)不會(huì)是最后一個(gè)使用 IsSuperMajority()來實(shí)現(xiàn)軟分叉的版本。BIP9 草案描述了version bits,這個(gè)草案仍然處于活躍狀態(tài),并持續(xù)變更。
Merkle Trees
(Merkle Tree的構(gòu)架和交易,工作量證明緊密相關(guān)。這里我們只介紹Merkle Tree的生成方法。其他的內(nèi)容,我們?cè)诤竺嬖敿?xì)說明。)
Merkle root 使用該區(qū)塊中全部的交易來進(jìn)行構(gòu)建,但是如一致性規(guī)則所要求的:
- 幣基交易的交易ID永遠(yuǎn)排在第一位
-
任何區(qū)塊內(nèi)交易的輸入都可以使用一個(gè)區(qū)塊內(nèi)交易的輸出(假頂消費(fèi)是合法的)。同時(shí),與輸出相關(guān)的交易ID必須在被用作其他交易的輸入前放置在某些位置,這個(gè)要求的目的是,便于使用線性方法解析區(qū)塊鏈的程序,在輸出被用作輸入前成功檢測(cè)每個(gè)輸出。
如果一個(gè)區(qū)塊只有幣基交易,那么該交易ID(conbase TXID)將被用作merkle root hash
如果一個(gè)區(qū)塊只有幣基交易和另外的一筆交易,二者的交易ID將會(huì)被合并做一個(gè)64字節(jié)的字符串,然后執(zhí)行SHA256(SHA256())獲得新的哈希值,并以該哈希值作為新的merkle root。
如果一個(gè)區(qū)塊擁有三個(gè)或三個(gè)以上的交易。交易ID則按照發(fā)生的順序,兩兩一組,拼接為64字節(jié)的字符串,然后執(zhí)行SHA256(SHA256())獲得對(duì)應(yīng)的哈希值。如果恰好有奇數(shù)個(gè)交易,那么最后一個(gè)交易與自身重復(fù),計(jì)算哈希值。如果一層內(nèi)有多于兩個(gè)的哈希值,那么我們就重復(fù)上述過程,直到只剩下兩個(gè)哈希值。利用最后的兩個(gè)哈希值來構(gòu)建Merkle root
Merkle Tree構(gòu)建示例
交易ID和中間層哈希值使用內(nèi)部字節(jié)順序,merkle root在保存在區(qū)塊頭時(shí),也使用內(nèi)部字節(jié)順序。
Target nBits
目標(biāo)閾值是一個(gè)256位無符號(hào)整數(shù)。區(qū)塊頭的哈希值必須不大于目標(biāo)閾值,才能通過工作量認(rèn)證和一致性規(guī)則成為區(qū)塊鏈的一部分。然而,區(qū)塊頭中只給nBits預(yù)留了32位空間,所以這里使用了一種低精度的被稱為“compact”格式的表示方法,該方法有些類似以256為基的科學(xué)表示法:

作為一個(gè)以256為基的數(shù)字,nBits可以像以10為基(十進(jìn)制)的數(shù)字一個(gè)快速寫出。

雖然目標(biāo)閾值應(yīng)該是一個(gè)無符號(hào)整數(shù),但是最初的nBits實(shí)現(xiàn)方法繼承與有符號(hào)數(shù)據(jù)類型,這意味著,目標(biāo)閾值可能會(huì)是個(gè)負(fù)數(shù)。但是這個(gè)無關(guān)緊要的問題,區(qū)塊頭哈希被標(biāo)示為一個(gè)無符號(hào)數(shù)字,所以它永遠(yuǎn)不可能小于一個(gè)負(fù)數(shù)。Bitcoin Core 使用兩種方法處理這個(gè)問題:
- 解析nBits時(shí),Bitcoin Core將會(huì)把目標(biāo)閾值為負(fù)數(shù)的情況直接轉(zhuǎn)換為0,這樣,就區(qū)塊頭的哈希值就可能成立了(至少理論上我們能得到一個(gè)值為0的哈希……)
- 當(dāng)生成nBits時(shí),Bitcoin Core將會(huì)檢查該nBits是否會(huì)被解析為一個(gè)負(fù)數(shù)的目標(biāo)閾值。如果真的被解析為負(fù)數(shù)的目標(biāo)閾值,那么我們對(duì)nBits進(jìn)行如下操作:我們將nBits除以256,然后在冪上加1。這樣,我們就獲得了一樣的目標(biāo)閾值,而采用了不同的nBits編碼方法。

挖礦難度最低為1,在正式環(huán)境和測(cè)試環(huán)境中,以0x1d00ffff表示。在回歸測(cè)試環(huán)境中,以0x207ffff來表示挖礦難度為1,這是小于uint_32的最大nbits值,這意味著,在回歸測(cè)試環(huán)境中,我們可以隨時(shí)重新構(gòu)建區(qū)塊鏈。
Serialized Blocks
依照當(dāng)前執(zhí)行的一致性規(guī)則,一個(gè)區(qū)塊序列化后占用空間大于1MB將被視為無效區(qū)塊。下面列出的字段都將參與序列化過程,并占用相關(guān)空間。
| 字節(jié)數(shù) | 名稱 | 數(shù)據(jù)類型 | 描述 |
|---|---|---|---|
| 80 | 區(qū)塊頭 | block_header | 關(guān)于區(qū)塊頭的格式,請(qǐng)參數(shù)區(qū)塊頭相關(guān)章節(jié) |
| 不定 | txn_count | CompactSize | 區(qū)塊中,包含幣基交易的全部交易數(shù)量 |
| 不定 | txns | raw transaction | 區(qū)塊中全部的以raw transaction格式存儲(chǔ)的交易信息。交易的排列順序必須符合merkle tree構(gòu)建時(shí)交易ID的順序。關(guān)于這個(gè)順序,可以查看剛剛說過的merkle tree構(gòu)建方法。 |
一個(gè)區(qū)塊內(nèi)的第一個(gè)交易一定是幣基交易(coinbase transaction),這個(gè)交易應(yīng)該收集和使用區(qū)塊內(nèi)全部的交易費(fèi)用。
所有的區(qū)塊高度低于6930K的區(qū)塊被發(fā)現(xiàn)的時(shí)候,都會(huì)收到額外的津貼,這個(gè)津貼應(yīng)該包含在幣基交易中。(最初每發(fā)現(xiàn)一個(gè)新區(qū)塊提供津貼50個(gè)比特幣,后續(xù)每210K個(gè)區(qū)塊津貼減半,基本上是每四年時(shí)間減半。到了2017年11月,該津貼是12.5個(gè)比特幣)
交易費(fèi)和挖礦津貼統(tǒng)一稱為區(qū)塊獎(jiǎng)勵(lì)。一個(gè)嘗試花費(fèi)高于區(qū)塊獎(jiǎng)勵(lì)的數(shù)額的幣基交易是非法的。
