區塊鏈 - 比特幣開發指南

原文鏈接: https://bitcoin.org/en/developer-guide#block-chain
翻譯:terryc007
版本: 1.0


比特幣開發指南

1. 區塊鏈

2. 交易

3.合約

4.錢包

5.支付處理

6.工作模式

7.P2P網絡

8.挖礦


比特幣開發指南主要是為你提供一些必要的信息,方面你理解比特幣,以及基于比特幣來開發一些應用程序。 但它并不是關于比特幣的說明書。 為了更好的使用本開發指南,你可以安裝當前比特幣核內核源碼,或者編譯好的比特幣內核客戶端

有關比特幣開發的問題,最好去比特幣開發社區提問。 在Bitcoin.org上,有關文檔的錯誤或建議,可作為一個問題提交,或在比特幣文檔郵件列表發貼。

在下面的開發文檔,有一些文字會被省略或隱藏起來: "[…]" 表示額外的數據已被刪掉,行尾帶有""符號,表示下面部分還是該行內容。如果你移動鼠標停在段落時,帶有交叉引用鏈接的文字會變成藍色。如果你把鼠標停在帶有交叉引用鏈接的術語上,會顯示這個術語的簡要提示信息。

區塊鏈

區塊鏈提供了比特幣公共賬簿,里面包含了有序的,帶有時間戳的交易記錄。區塊鏈系統被用來防止雙發,防止之前的交易記錄被篡改。

在比特幣網絡,每個全節點,各自獨立的保存了一份區塊鏈,該區塊鏈中包含僅由自己驗證的區塊數據。當節點的區塊鏈中,都有相同的區塊時,他們被認為有一致的共識。這些被用節點來維持共識的驗證規則叫做共識規則。 本節會介紹很多在比特幣內核中用到共識規則

區塊鏈概要

上面的插圖是個簡易版區塊鏈。一條或多條新的交易記錄被收集到區塊中,用于存放交易數據的地方。為每條交易生成哈希值,然后哈希值兩兩配對,再生成哈希值, 然后再對之前的生成的哈希值兩兩配對,再生成哈希,直到只剩下一個哈希值,最后這個哈希值就是默克樹根。

默克爾樹根被存放在區塊頭。每個區塊會存放前一個區塊頭的哈希值,這樣把所有的區塊串聯起來,便成了區塊鏈。 這就保證了,在不修改交易所在的區塊,以及該區塊后續所有區塊前提下,交易是不能被篡改的。

交易記錄也會被串聯在一起。比特幣錢包給我們一個直觀的印象是:satoshis(比特幣最少的單位 1btc = 100,000,000 satoshis)在錢包之間來回發送,但實際上比特幣是從一個交易到另外一個交易的轉移。 每個交易會花之前一個或多個交易的satoshis,所以一個交易的輸入就是前一個交易的輸出

一個交易可以創建多個輸出,就如同當發送到多個地址,但在區塊鏈中,每個特定的交易輸出只能被交易輸入使用一次。任何后續的引用都是一個禁止的雙發 — 試圖使用兩次satoshis

交易輸出會跟交易id(TXIDS)綁定在一起,所謂的交易id就是交易的哈希值。

因為每個特定交易的輸出只能被使用一次,區塊鏈中所有的交易的輸出可以被歸類為: 未使用交易輸出(UTXOs)或者 發費交易輸出。對于一個有效的支付,它必須且只能使用UTXOs作為輸入。

coinbase類型交易(區塊中的第一個交易,通常被礦工創建,用來認領挖礦獎勵,以及提供100個字節的空間,可存放任何數據)外,如果一個交易的輸出值大于它的輸入值,交易將會被拒絕。 但是如果交易輸入值大于交易輸出值,其中的差額就是交易費用,用于支付比特幣礦工(他們負責創建包含交易的區塊)。比如,在上面的圖示中,每個交易交易費用少于交易輸入總和,實際上支付了10000 satoshis。

工作量證明

網絡中的匿名節點一起協作來維持區塊鏈,因此比特幣在創建區塊時,需要一個有效數量的工作證明,以確保試圖修改歷史區塊的不可信節點,比起可信的節點付出更多的工作量。

把區塊串聯起來,在不修改當前區塊以及后續所有區塊情況下,使得修改任何區塊中的交易變的不可能。因此,每增加一個新的區塊到區塊鏈上,就會增加修改一個特定區塊的成本,也就放大了工作量證明的效果。

比特幣中使用的工作量證明利用了密碼學哈希中的自然隨機。一個好的加密哈希算法可把任意數據轉化成看似隨機的數字。如果數據修改,不管任何方式,當重新計算數據的哈希值時,會產生一個新的隨機數,因此沒有任何方法在修改數據之后,可以預測其哈希值。

為了證明你為創建區塊而做了一些工作,你必須生成一個區塊頭的哈希值,該哈希值不能超過一個特定的值。比如,如果最大的哈希值是2256-1 , 你可通過生成一個小于2255的哈希值來證明你嘗試了兩種組合。[?]

在上面的例子中,你生成一個符合要求的哈希值所做的每次嘗試在概率上是相同的。 甚至可以估算出一次哈希計算嘗試能生成一個小于特哈希值的概率。比特幣采用的是線性概率 , 即哈希目標值越小,就需要越多的哈希計算嘗試。

新區塊只有其生成的哈希值,符合共識協議所預期的難度值,才能被加入到區塊鏈中。 每2016個區塊,比特幣網絡使用保存在區塊頭中的時間戳,來計算從生成第一個區塊到第2016個區塊所經歷的時間(秒)。這實際的值是 1209600秒(兩個星期)。

  • 如果生成2016個區塊所用的時間少于2個星期,那么生成下2016個區塊時,在同一算力的情況下,為保證2016個區塊生成所需的時間,恰好是2個星期,那么預期的難度值會按比例提升(差不多300%)。

  • 如果生成2016個區塊所用的時間多于2個星期,同理,其預期難度會按比例下調(大約75%)。

(注意:在比特幣內核實現中,一個單個偏移的錯誤導致難度的更新從僅需2015個區塊變成了2016個區塊,這了導致了一點偏移)[?]。

因為每個區塊頭在生成哈希值時,必須要小于目標閥值,同時每個區塊要跟它之前的區塊鏈接起來,要在整個比特幣網絡中廣播修改過的區塊,平均上講,它就需要消耗:從被修改的區塊其創建時間起,到當前時間之間所有區塊需要的算力。 只有你掌握了大量的哈希算力,你才能可靠的執行51算力攻擊(然而需要注意的是,即使是低于50%的哈希算力, 也是有可能成功的實施這樣的攻擊)。

區塊頭提供了好幾個易于修改的字段,比如一個專用的臨時字段,這樣可以在不需要等待新的交易,就可以獲得新的哈希值。[?] 同樣,用于工作量證明時,只需對只有80個字節的區塊頭計算哈希值就可以,所以在區塊中大量的交易數據并不會降低計算哈希值的速度,而只是增加了一些額外的交易數據,需要重新計算默克樹中的父節點哈希值。

區塊高度和分叉

任何比特幣礦工可以把整個區塊加入到區塊鏈中,只要它生成的區塊頭哈希值低于目標閥值。這些區塊通過區塊高度來尋址。所謂的區塊高度 - 指的是當前區塊到第一個比特幣區塊(通常也叫創世塊)之間區塊的個數。比如,區塊高度為2016的區塊,就是第一次難度調節后的區塊。

多個區塊可以同時有相同的區塊高度,因為當二個或多個礦工在同一時間產出一個區塊是很常見的。這會在區塊鏈創建一個明顯的分叉,如下圖所示。

當礦工在區塊鏈末端同時產出多個區塊時,每個節點會各自接受區塊。在不考慮其他節點的情況下,節點通常會選擇他們第一次看到的區塊,下面我們會討論。

最終,每個礦工會產出另外一個區塊,它會被添加到具有并發競爭挖取的區塊鏈中[?]。這使得分叉鏈比其他側鏈難度更大。假如一個分叉僅包含有效的區塊,普通的節點通常會基于難度最大的鏈進行重建區塊鏈,同時會剔除掉屬于較短鏈上的陳腐區塊(有時候也叫孤塊,但是孤塊,也用來表示那些沒有父區塊的區塊。)。

陳腐區塊

就是那些不在難度最大的區塊鏈上,而在其他分叉側鏈上的區塊,有時候也叫孤塊,但是也指那些還沒有被本地節點處理的,沒有父區塊的區塊。

很長的分叉是有可能的。 比如不同的礦工為不同的目的而工作,比如一些礦工勤懇的擴展區塊鏈,同時,其他的礦工企圖通過實施51%算力攻擊修改交易記錄。

在一個分叉鏈上,因為多個區塊可能其區塊高度是一樣的,因此,區塊高度不能用于全局唯一標識。而是,通過區塊的區塊頭的哈希值(16進制,反字節序)來引用區塊。

交易數據

每個區塊必須包含一個,或多個交易。第一個交易必須是coinbase交易。也叫創世交易。它用來接收,消費區塊獎勵(包括挖出一個區塊的補貼,以及該區塊內所有交易支付的交易費用)。

創世交易的UTXO有一個特定的條款,就是少于100個區塊確認,它是不能被發掉的(即不能做為其他交易的輸入)。這可暫時防止礦工發掉從區塊獲取的區塊獎勵,因為在一個分叉的鏈上,礦工挖出的區塊有可能以后被認定為是孤塊。

區塊并不要求包含任何非coinbase交易,但是礦工為了獲得他們的交易費用,他們幾乎總是會往區塊中加一些額外的交易。

所以的交易,包括coinbase交易,會以二進制源交易[?]格式編碼存儲到區塊中。

通過對源交易格式進行哈希來生成交易id(txid). 對于這些交易id,通過對txid兩兩配對,讓后對他們進行哈希計算,來構建默克爾樹。如果是個奇數個交易id,則跟自己配對來實現兩兩配對,再進行哈希計算。

這些哈希計算結果(即哈希值)讓后又兩兩配對,再計算哈希值。任何哈希值如果沒有配對的,就跟自己配對,再計算哈希值。這個過程會不斷的重復,直到只剩下一個哈希值。這個值就是默克樹根。

比如,如果交易不做哈希處理,那么5個交易的默克爾樹看起來如下圖所示:

 ABCDEEEE .......Merkle root
        /        \
     ABCD        EEEE
    /    \      /
   AB    CD    EE .......E is paired with itself
  /  \  /  \  /
  A  B  C  D  E .........Transactions

如簡化支付認證(SPV)段落中所討論的,通過區塊頭中的默克爾樹根,以及從一個全節點中獲取的,一個中間哈希值列表[?],默克爾樹允許客戶端根自己驗證一個交易是否在一個區塊中。全節點不必是可信的,因為偽造區塊頭的成本很高,同時中間哈希值列表是不能偽造的,否則驗證會失敗。

比如,要驗證交易D是否已被加入區塊中,一個SPV客戶端僅需要交易C,AB,EEEE的哈希值,以及區塊的默克爾樹根;客戶端不需要知道其他任何交易。在這個區塊中,假如按這個5個交易所占最大的大小來算,下載這整個區塊需要大約500,000字節 - 但是下載3個哈希值,再加上區塊頭僅需要140字節。

注意: 如果在同一個區塊中發現相同的交易id,默克爾樹可能會跟區塊發生沖突, 會導致一些或者全部交易id被刪掉去,這取決于非平衡默克爾樹[?]是如何實現的(復制孤立的哈希值)。 因為不同交易有相同的交易id是不可能的,這對于那些忠實的軟件不是一個負擔,但是如果一個區塊的無效狀態被緩存,那么必須要對該區塊進行檢查;否則,一個去除重復交易id的有效區塊本可以有相同的默克爾樹根,區塊哈希值,但因緩存的無效的區塊狀態,會導致安全bug(比如)CVE-2012-2459, 而使得區塊被拒絕掉。

共識規則改變

為維持共識,所以的全節點使用同樣的共識規則來驗證區塊。然而,有時候為了引進新的功能以防止比特幣網的濫用,就需要對共識規則進行改變。當新的共識規則被實施后,非升級節點會繼續遵循久的共識規則,升級節點遵循新的共識規則,這種情況可能會持續一段時間,這樣會導致兩種不同的共識。

  1. 遵循新共識規則的區塊被升級節點接受,但非升級節點會拒絕接受。比如,一個的交易功能在被區塊使用: 升級節點知道這個功能并接受它,而非升級節點因其他違反老的共識規則而拒絕接受它。

  2. 違反新的共識規則的區塊被升級節點拒絕,但被非升級節點接受。比如,一個濫用的交易功能在區塊中使用:升級節點會拒絕它,因為它違反了新的共識規則,而非升級節點則接受它,因為它遵守了老的共識規則。

在第一種情況,非升級節點拒絕接受,那些從非升級節點獲取區塊數據的挖礦軟件,拒絕構建跟那些從升級節點獲取區塊數據的挖礦軟件同樣的區塊鏈。這會創建永久的分叉 — 一個非升級節點所在的鏈,一個升級節點所在的鏈 — 這也叫做硬分叉。

在第二種情況,區塊被升級節點拒絕接受,如果升級節點控制了絕大部分哈希算力,那么避免硬分叉是有可能的。這是因為,在這種情況,非升級節點會接受所有升級節點中有效的區塊,因此升級節點能構建更為健壯的區塊鏈,而非升級節點會接受這條鏈是最好的有效鏈。 這叫做軟分叉

雖然分叉在區塊鏈中是一個真實的分歧,但是修改共識規則通常使用創建一個硬分叉或軟分叉來描述。比如,“增加區塊大小到1MB以上需要一個硬分叉”,在這個例子中,是個實際的區塊鏈分叉是不需要的 — 但是這是一個可能的方案。

共識規則的改變可以通過各種方式來激活。在比特幣的頭兩年,中本聰就通過執行過好幾次軟分叉,他通過發布向后兼容的共識規則更改的客戶端,使得這些客戶端立即執行新的共識規則。很多的軟分叉,如BIP30 ,是通過一個標志日期來激活。就是說新的共識規則在預定的時間或者區塊高度被強制激活。像這種通過標志日期來激活的分叉被稱之為用戶激活軟分叉(UASF)。因為在標志日期后,這些分叉要依賴一些有效的用戶(節點)去執行新的共識規則。

后來,軟叉需要等待大部分哈希算力(通常75%或95%)發出他們已準備好執行新的共識規則的信號。一旦超過所需信號的閾值,所以的節點就會執行新的共識規則。這樣的分叉被稱之為礦工激活軟分叉(MASF),因為分叉依賴礦工去激活。

資源: BIP16, BIP30, BIP34 是通過共識規則的改變來實施的,導致了軟分叉。 BIP50 導致了一個意外的硬分叉,后來通過臨時降級升級節點的能力,以及當臨時的降級被移除后,通過一個有意的硬分叉來解決這個問題。這有一個來自Gavin Andresen,有關未來共識規則改變如何實施的文檔。

檢測分叉

在上面兩種分叉中,非升級節點可以使用,發送不正確的信息,會創建好幾個情況導致財產損失。實際上,非升級節點可以轉發,接受那些被升級節點認為無效的交易。這些交易永遠不會成為全局公認的最佳區塊鏈中的一部分。非升級節點也可以拒絕轉發那些已經添加,或即將添加到最佳區塊鏈中的區塊,交易,這樣就可以提供不完整的信息。

比特幣內核里有通過查看區塊鏈工作量證明實現檢測硬分叉的代碼。如果非升級節點收到一些區塊頭,這些區塊頭里面至少有6個區塊可以證明,新區塊所在的區塊鏈的工作量,比起該節點認為的最佳區塊鏈上的工作量還要多的話,則該節點會在getnetworkinfo RPC結果中報告一個警告,同時,會運行 -alertnotify 命令,如果有設置的話。這會警告運營者非升級節點不能切換到很有可能是最佳的區塊鏈上。

全節點也能檢查區塊,交易的版本號。如果最近的區塊的區塊版本號或交易版本號,比改節點用的區塊的版本號要高,它就會認為它沒有使用當前的共識規則。比特幣內核會通過getnetworkinfo RPC 來報告這個情況,以及運行-alertnotify命令,如果有設置的話。

不論哪種情況,如果區塊,交易數據明顯來自一個沒有使用當前共識協議的節點,區塊,交易數據就不應該被轉發。

SPV客戶端會跟全節點鏈接起來,通過鏈接多個全節點,同時保證這些全節點在同一區塊鏈的同一個區塊高度,考慮到交易延遲,陳腐區塊,可加或減掉幾個區塊,就可以檢測可能的硬分叉。如果有分叉,SPV客戶端可以斷掉那些在更弱鏈上節點間的連接。

SPV客戶端也應監控區塊,交易版本號的增加,這樣可以保證SPV客戶端去處理接收到的交易,并使用新的共識規則創建新的交易。


聲明:

文中帶有[?]的地方,表示我對此翻譯明顯感覺不太對的,后續會不斷修正。

初次翻譯,可能會有些地方翻譯的不好,不地道,甚至錯誤,如果有發現,還請留言,指出,以便我好修正,謝謝!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容