原文鏈接: https://bitcoin.org/en/developer-guide#block-chain
翻譯:terryc007
版本: 1.0
比特幣開發(fā)指南
比特幣開發(fā)指南主要是為你提供一些必要的信息,方面你理解比特幣,以及基于比特幣來開發(fā)一些應(yīng)用程序呆万。 但它并不是關(guān)于比特幣的說明書斋配。 為了更好的使用本開發(fā)指南却桶,你可以安裝當(dāng)前比特幣核內(nèi)核源碼惋增,或者編譯好的比特幣內(nèi)核客戶端。
有關(guān)比特幣開發(fā)的問題肆良,最好去比特幣開發(fā)社區(qū)提問纺弊。 在Bitcoin.org上牛欢,有關(guān)文檔的錯誤或建議,可作為一個問題提交淆游,或在比特幣文檔郵件列表發(fā)貼傍睹。
在下面的開發(fā)文檔,有一些文字會被省略或隱藏起來: "[…]" 表示額外的數(shù)據(jù)已被刪掉犹菱,行尾帶有""符號拾稳,表示下面部分還是該行內(nèi)容。如果你移動鼠標(biāo)停在段落時腊脱,帶有交叉引用鏈接的文字會變成藍色访得。如果你把鼠標(biāo)停在帶有交叉引用鏈接的術(shù)語上,會顯示這個術(shù)語的簡要提示信息陕凹。
區(qū)塊鏈
區(qū)塊鏈提供了比特幣公共賬簿悍抑,里面包含了有序的鳄炉,帶有時間戳的交易記錄。區(qū)塊鏈系統(tǒng)被用來防止雙發(fā)传趾,防止之前的交易記錄被篡改。
在比特幣網(wǎng)絡(luò)泥技,每個全節(jié)點浆兰,各自獨立的保存了一份區(qū)塊鏈,該區(qū)塊鏈中包含僅由自己驗證的區(qū)塊數(shù)據(jù)珊豹。當(dāng)節(jié)點的區(qū)塊鏈中簸呈,都有相同的區(qū)塊時,他們被認為有一致的共識店茶。這些被用節(jié)點來維持共識的驗證規(guī)則叫做共識規(guī)則蜕便。 本節(jié)會介紹很多在比特幣內(nèi)核中用到共識規(guī)則。
區(qū)塊鏈概要
上面的插圖是個簡易版區(qū)塊鏈贩幻。一條或多條新的交易記錄被收集到區(qū)塊中轿腺,用于存放交易數(shù)據(jù)的地方。為每條交易生成哈希值丛楚,然后哈希值兩兩配對族壳,再生成哈希值, 然后再對之前的生成的哈希值兩兩配對趣些,再生成哈希仿荆,直到只剩下一個哈希值,最后這個哈希值就是默克樹根坏平。
默克爾樹根被存放在區(qū)塊頭拢操。每個區(qū)塊會存放前一個區(qū)塊頭的哈希值,這樣把所有的區(qū)塊串聯(lián)起來舶替,便成了區(qū)塊鏈令境。 這就保證了,在不修改交易所在的區(qū)塊顾瞪,以及該區(qū)塊后續(xù)所有區(qū)塊前提下展父,交易是不能被篡改的。
交易記錄也會被串聯(lián)在一起玲昧。比特幣錢包給我們一個直觀的印象是:satoshis(比特幣最少的單位 1btc = 100,000,000 satoshis)在錢包之間來回發(fā)送栖茉,但實際上比特幣是從一個交易到另外一個交易的轉(zhuǎn)移。 每個交易會花之前一個或多個交易的satoshis孵延,所以一個交易的輸入就是前一個交易的輸出吕漂。
一個交易可以創(chuàng)建多個輸出,就如同當(dāng)發(fā)送到多個地址尘应,但在區(qū)塊鏈中惶凝,每個特定的交易輸出只能被交易輸入使用一次吼虎。任何后續(xù)的引用都是一個禁止的雙發(fā) — 試圖使用兩次satoshis。
交易輸出會跟交易id(TXIDS)綁定在一起苍鲜,所謂的交易id就是交易的哈希值思灰。
因為每個特定交易的輸出只能被使用一次,區(qū)塊鏈中所有的交易的輸出可以被歸類為: 未使用交易輸出(UTXOs)或者 發(fā)費交易輸出混滔。對于一個有效的支付洒疚,它必須且只能使用UTXOs作為輸入。
除coinbase類型交易(區(qū)塊中的第一個交易坯屿,通常被礦工創(chuàng)建油湖,用來認領(lǐng)挖礦獎勵,以及提供100個字節(jié)的空間领跛,可存放任何數(shù)據(jù))外乏德,如果一個交易的輸出值大于它的輸入值,交易將會被拒絕吠昭。 但是如果交易輸入值大于交易輸出值喊括,其中的差額就是交易費用,用于支付比特幣礦工(他們負責(zé)創(chuàng)建包含交易的區(qū)塊)矢棚。比如瘾晃,在上面的圖示中,每個交易交易費用少于交易輸入總和幻妓,實際上支付了10000 satoshis蹦误。
工作量證明
網(wǎng)絡(luò)中的匿名節(jié)點一起協(xié)作來維持區(qū)塊鏈,因此比特幣在創(chuàng)建區(qū)塊時肉津,需要一個有效數(shù)量的工作證明强胰,以確保試圖修改歷史區(qū)塊的不可信節(jié)點,比起可信的節(jié)點付出更多的工作量妹沙。
把區(qū)塊串聯(lián)起來偶洋,在不修改當(dāng)前區(qū)塊以及后續(xù)所有區(qū)塊情況下,使得修改任何區(qū)塊中的交易變的不可能距糖。因此玄窝,每增加一個新的區(qū)塊到區(qū)塊鏈上,就會增加修改一個特定區(qū)塊的成本悍引,也就放大了工作量證明的效果恩脂。
比特幣中使用的工作量證明利用了密碼學(xué)哈希中的自然隨機。一個好的加密哈希算法可把任意數(shù)據(jù)轉(zhuǎn)化成看似隨機的數(shù)字趣斤。如果數(shù)據(jù)修改俩块,不管任何方式,當(dāng)重新計算數(shù)據(jù)的哈希值時,會產(chǎn)生一個新的隨機數(shù)玉凯,因此沒有任何方法在修改數(shù)據(jù)之后势腮,可以預(yù)測其哈希值。
為了證明你為創(chuàng)建區(qū)塊而做了一些工作漫仆,你必須生成一個區(qū)塊頭的哈希值捎拯,該哈希值不能超過一個特定的值。比如盲厌,如果最大的哈希值是2256-1 , 你可通過生成一個小于2255的哈希值來證明你嘗試了兩種組合署照。[?]
在上面的例子中,你生成一個符合要求的哈希值所做的每次嘗試在概率上是相同的狸眼。 甚至可以估算出一次哈希計算嘗試能生成一個小于特哈希值的概率藤树。比特幣采用的是線性概率 浴滴, 即哈希目標(biāo)值越小拓萌,就需要越多的哈希計算嘗試。
新區(qū)塊只有其生成的哈希值升略,符合共識協(xié)議所預(yù)期的難度值微王,才能被加入到區(qū)塊鏈中。 每2016個區(qū)塊品嚣,比特幣網(wǎng)絡(luò)使用保存在區(qū)塊頭中的時間戳炕倘,來計算從生成第一個區(qū)塊到第2016個區(qū)塊所經(jīng)歷的時間(秒)。這實際的值是 1209600秒(兩個星期)翰撑。
如果生成2016個區(qū)塊所用的時間少于2個星期罩旋,那么生成下2016個區(qū)塊時,在同一算力的情況下眶诈,為保證2016個區(qū)塊生成所需的時間涨醋,恰好是2個星期,那么預(yù)期的難度值會按比例提升(差不多300%)逝撬。
如果生成2016個區(qū)塊所用的時間多于2個星期浴骂,同理,其預(yù)期難度會按比例下調(diào)(大約75%)宪潮。
(注意:在比特幣內(nèi)核實現(xiàn)中溯警,一個單個偏移的錯誤導(dǎo)致難度的更新從僅需2015個區(qū)塊變成了2016個區(qū)塊,這了導(dǎo)致了一點偏移)[?]狡相。
因為每個區(qū)塊頭在生成哈希值時梯轻,必須要小于目標(biāo)閥值,同時每個區(qū)塊要跟它之前的區(qū)塊鏈接起來尽棕,要在整個比特幣網(wǎng)絡(luò)中廣播修改過的區(qū)塊檩淋,平均上講,它就需要消耗:從被修改的區(qū)塊其創(chuàng)建時間起,到當(dāng)前時間之間所有區(qū)塊需要的算力蟀悦。 只有你掌握了大量的哈希算力媚朦,你才能可靠的執(zhí)行51算力攻擊(然而需要注意的是,即使是低于50%的哈希算力日戈, 也是有可能成功的實施這樣的攻擊)询张。
區(qū)塊頭提供了好幾個易于修改的字段,比如一個專用的臨時字段浙炼,這樣可以在不需要等待新的交易份氧,就可以獲得新的哈希值。[?] 同樣弯屈,用于工作量證明時蜗帜,只需對只有80個字節(jié)的區(qū)塊頭計算哈希值就可以,所以在區(qū)塊中大量的交易數(shù)據(jù)并不會降低計算哈希值的速度资厉,而只是增加了一些額外的交易數(shù)據(jù)厅缺,需要重新計算默克樹中的父節(jié)點哈希值。
區(qū)塊高度和分叉
任何比特幣礦工可以把整個區(qū)塊加入到區(qū)塊鏈中宴偿,只要它生成的區(qū)塊頭哈希值低于目標(biāo)閥值湘捎。這些區(qū)塊通過區(qū)塊高度來尋址。所謂的區(qū)塊高度 - 指的是當(dāng)前區(qū)塊到第一個比特幣區(qū)塊(通常也叫創(chuàng)世塊)之間區(qū)塊的個數(shù)窄刘。比如窥妇,區(qū)塊高度為2016的區(qū)塊,就是第一次難度調(diào)節(jié)后的區(qū)塊娩践。
多個區(qū)塊可以同時有相同的區(qū)塊高度活翩,因為當(dāng)二個或多個礦工在同一時間產(chǎn)出一個區(qū)塊是很常見的。這會在區(qū)塊鏈創(chuàng)建一個明顯的分叉翻伺,如下圖所示材泄。
當(dāng)?shù)V工在區(qū)塊鏈末端同時產(chǎn)出多個區(qū)塊時,每個節(jié)點會各自接受區(qū)塊穆趴。在不考慮其他節(jié)點的情況下脸爱,節(jié)點通常會選擇他們第一次看到的區(qū)塊,下面我們會討論未妹。
最終簿废,每個礦工會產(chǎn)出另外一個區(qū)塊,它會被添加到具有并發(fā)競爭挖取的區(qū)塊鏈中[?]络它。這使得分叉鏈比其他側(cè)鏈難度更大族檬。假如一個分叉僅包含有效的區(qū)塊,普通的節(jié)點通常會基于難度最大的鏈進行重建區(qū)塊鏈化戳,同時會剔除掉屬于較短鏈上的陳腐區(qū)塊(有時候也叫孤塊单料,但是孤塊埋凯,也用來表示那些沒有父區(qū)塊的區(qū)塊。)扫尖。
陳腐區(qū)塊
就是那些不在難度最大的區(qū)塊鏈上白对,而在其他分叉?zhèn)孺溕系膮^(qū)塊,有時候也叫孤塊换怖,但是也指那些還沒有被本地節(jié)點處理的甩恼,沒有父區(qū)塊的區(qū)塊。
很長的分叉是有可能的沉颂。 比如不同的礦工為不同的目的而工作条摸,比如一些礦工勤懇的擴展區(qū)塊鏈,同時铸屉,其他的礦工企圖通過實施51%算力攻擊修改交易記錄钉蒲。
在一個分叉鏈上,因為多個區(qū)塊可能其區(qū)塊高度是一樣的彻坛,因此顷啼,區(qū)塊高度不能用于全局唯一標(biāo)識。而是小压,通過區(qū)塊的區(qū)塊頭的哈希值(16進制线梗,反字節(jié)序)來引用區(qū)塊椰于。
交易數(shù)據(jù)
每個區(qū)塊必須包含一個怠益,或多個交易。第一個交易必須是coinbase交易瘾婿。也叫創(chuàng)世交易蜻牢。它用來接收,消費區(qū)塊獎勵(包括挖出一個區(qū)塊的補貼偏陪,以及該區(qū)塊內(nèi)所有交易支付的交易費用)抢呆。
創(chuàng)世交易的UTXO有一個特定的條款,就是少于100個區(qū)塊確認笛谦,它是不能被發(fā)掉的(即不能做為其他交易的輸入)抱虐。這可暫時防止礦工發(fā)掉從區(qū)塊獲取的區(qū)塊獎勵,因為在一個分叉的鏈上饥脑,礦工挖出的區(qū)塊有可能以后被認定為是孤塊恳邀。
區(qū)塊并不要求包含任何非coinbase交易,但是礦工為了獲得他們的交易費用灶轰,他們幾乎總是會往區(qū)塊中加一些額外的交易谣沸。
所以的交易,包括coinbase交易笋颤,會以二進制源交易[?]格式編碼存儲到區(qū)塊中乳附。
通過對源交易格式進行哈希來生成交易id(txid). 對于這些交易id,通過對txid兩兩配對,讓后對他們進行哈希計算赋除,來構(gòu)建默克爾樹阱缓。如果是個奇數(shù)個交易id,則跟自己配對來實現(xiàn)兩兩配對举农,再進行哈希計算茬祷。
這些哈希計算結(jié)果(即哈希值)讓后又兩兩配對,再計算哈希值并蝗。任何哈希值如果沒有配對的祭犯,就跟自己配對,再計算哈希值滚停。這個過程會不斷的重復(fù)沃粗,直到只剩下一個哈希值。這個值就是默克樹根键畴。
比如最盅,如果交易不做哈希處理,那么5個交易的默克爾樹看起來如下圖所示:
ABCDEEEE .......Merkle root
/ \
ABCD EEEE
/ \ /
AB CD EE .......E is paired with itself
/ \ / \ /
A B C D E .........Transactions
如簡化支付認證(SPV)段落中所討論的起惕,通過區(qū)塊頭中的默克爾樹根涡贱,以及從一個全節(jié)點中獲取的,一個中間哈希值列表[?]惹想,默克爾樹允許客戶端根自己驗證一個交易是否在一個區(qū)塊中问词。全節(jié)點不必是可信的,因為偽造區(qū)塊頭的成本很高嘀粱,同時中間哈希值列表是不能偽造的激挪,否則驗證會失敗。
比如锋叨,要驗證交易D是否已被加入?yún)^(qū)塊中垄分,一個SPV客戶端僅需要交易C,AB,EEEE的哈希值,以及區(qū)塊的默克爾樹根娃磺;客戶端不需要知道其他任何交易薄湿。在這個區(qū)塊中,假如按這個5個交易所占最大的大小來算偷卧,下載這整個區(qū)塊需要大約500,000字節(jié) - 但是下載3個哈希值豺瘤,再加上區(qū)塊頭僅需要140字節(jié)。
注意: 如果在同一個區(qū)塊中發(fā)現(xiàn)相同的交易id涯冠,默克爾樹可能會跟區(qū)塊發(fā)生沖突, 會導(dǎo)致一些或者全部交易id被刪掉去炉奴,這取決于非平衡默克爾樹[?]是如何實現(xiàn)的(復(fù)制孤立的哈希值)。 因為不同交易有相同的交易id是不可能的蛇更,這對于那些忠實的軟件不是一個負擔(dān)瞻赶,但是如果一個區(qū)塊的無效狀態(tài)被緩存赛糟,那么必須要對該區(qū)塊進行檢查;否則砸逊,一個去除重復(fù)交易id的有效區(qū)塊本可以有相同的默克爾樹根璧南,區(qū)塊哈希值,但因緩存的無效的區(qū)塊狀態(tài)师逸,會導(dǎo)致安全bug(比如)CVE-2012-2459司倚, 而使得區(qū)塊被拒絕掉。
共識規(guī)則改變
為維持共識篓像,所以的全節(jié)點使用同樣的共識規(guī)則來驗證區(qū)塊动知。然而,有時候為了引進新的功能以防止比特幣網(wǎng)的濫用员辩,就需要對共識規(guī)則進行改變盒粮。當(dāng)新的共識規(guī)則被實施后,非升級節(jié)點會繼續(xù)遵循久的共識規(guī)則奠滑,升級節(jié)點遵循新的共識規(guī)則丹皱,這種情況可能會持續(xù)一段時間,這樣會導(dǎo)致兩種不同的共識宋税。
遵循新共識規(guī)則的區(qū)塊被升級節(jié)點接受摊崭,但非升級節(jié)點會拒絕接受。比如杰赛,一個的交易功能在被區(qū)塊使用: 升級節(jié)點知道這個功能并接受它呢簸,而非升級節(jié)點因其他違反老的共識規(guī)則而拒絕接受它。
違反新的共識規(guī)則的區(qū)塊被升級節(jié)點拒絕淆攻,但被非升級節(jié)點接受阔墩。比如嘿架,一個濫用的交易功能在區(qū)塊中使用:升級節(jié)點會拒絕它瓶珊,因為它違反了新的共識規(guī)則,而非升級節(jié)點則接受它耸彪,因為它遵守了老的共識規(guī)則伞芹。
在第一種情況,非升級節(jié)點拒絕接受蝉娜,那些從非升級節(jié)點獲取區(qū)塊數(shù)據(jù)的挖礦軟件唱较,拒絕構(gòu)建跟那些從升級節(jié)點獲取區(qū)塊數(shù)據(jù)的挖礦軟件同樣的區(qū)塊鏈。這會創(chuàng)建永久的分叉 — 一個非升級節(jié)點所在的鏈召川,一個升級節(jié)點所在的鏈 — 這也叫做硬分叉南缓。
在第二種情況,區(qū)塊被升級節(jié)點拒絕接受荧呐,如果升級節(jié)點控制了絕大部分哈希算力汉形,那么避免硬分叉是有可能的纸镊。這是因為,在這種情況概疆,非升級節(jié)點會接受所有升級節(jié)點中有效的區(qū)塊逗威,因此升級節(jié)點能構(gòu)建更為健壯的區(qū)塊鏈,而非升級節(jié)點會接受這條鏈是最好的有效鏈岔冀。 這叫做軟分叉凯旭。
雖然分叉在區(qū)塊鏈中是一個真實的分歧,但是修改共識規(guī)則通常使用創(chuàng)建一個硬分叉或軟分叉來描述使套。比如罐呼,“增加區(qū)塊大小到1MB以上需要一個硬分叉”,在這個例子中侦高,是個實際的區(qū)塊鏈分叉是不需要的 — 但是這是一個可能的方案弄贿。
共識規(guī)則的改變可以通過各種方式來激活。在比特幣的頭兩年矫膨,中本聰就通過執(zhí)行過好幾次軟分叉差凹,他通過發(fā)布向后兼容的共識規(guī)則更改的客戶端,使得這些客戶端立即執(zhí)行新的共識規(guī)則侧馅。很多的軟分叉危尿,如BIP30 ,是通過一個標(biāo)志日期來激活馁痴。就是說新的共識規(guī)則在預(yù)定的時間或者區(qū)塊高度被強制激活谊娇。像這種通過標(biāo)志日期來激活的分叉被稱之為用戶激活軟分叉(UASF)。因為在標(biāo)志日期后罗晕,這些分叉要依賴一些有效的用戶(節(jié)點)去執(zhí)行新的共識規(guī)則济欢。
后來,軟叉需要等待大部分哈希算力(通常75%或95%)發(fā)出他們已準備好執(zhí)行新的共識規(guī)則的信號小渊。一旦超過所需信號的閾值法褥,所以的節(jié)點就會執(zhí)行新的共識規(guī)則。這樣的分叉被稱之為礦工激活軟分叉(MASF),因為分叉依賴礦工去激活酬屉。
資源: BIP16, BIP30, BIP34 是通過共識規(guī)則的改變來實施的半等,導(dǎo)致了軟分叉。 BIP50 導(dǎo)致了一個意外的硬分叉呐萨,后來通過臨時降級升級節(jié)點的能力杀饵,以及當(dāng)臨時的降級被移除后,通過一個有意的硬分叉來解決這個問題谬擦。這有一個來自Gavin Andresen切距,有關(guān)未來共識規(guī)則改變?nèi)绾螌嵤?/a>的文檔。
檢測分叉
在上面兩種分叉中惨远,非升級節(jié)點可以使用谜悟,發(fā)送不正確的信息饵沧,會創(chuàng)建好幾個情況導(dǎo)致財產(chǎn)損失。實際上赌躺,非升級節(jié)點可以轉(zhuǎn)發(fā)狼牺,接受那些被升級節(jié)點認為無效的交易。這些交易永遠不會成為全局公認的最佳區(qū)塊鏈中的一部分礼患。非升級節(jié)點也可以拒絕轉(zhuǎn)發(fā)那些已經(jīng)添加是钥,或即將添加到最佳區(qū)塊鏈中的區(qū)塊,交易缅叠,這樣就可以提供不完整的信息悄泥。
比特幣內(nèi)核里有通過查看區(qū)塊鏈工作量證明實現(xiàn)檢測硬分叉的代碼。如果非升級節(jié)點收到一些區(qū)塊頭肤粱,這些區(qū)塊頭里面至少有6個區(qū)塊可以證明弹囚,新區(qū)塊所在的區(qū)塊鏈的工作量,比起該節(jié)點認為的最佳區(qū)塊鏈上的工作量還要多的話领曼,則該節(jié)點會在getnetworkinfo
RPC結(jié)果中報告一個警告鸥鹉,同時,會運行 -alertnotify
命令庶骄,如果有設(shè)置的話毁渗。這會警告運營者非升級節(jié)點不能切換到很有可能是最佳的區(qū)塊鏈上。
全節(jié)點也能檢查區(qū)塊单刁,交易的版本號灸异。如果最近的區(qū)塊的區(qū)塊版本號或交易版本號,比改節(jié)點用的區(qū)塊的版本號要高羔飞,它就會認為它沒有使用當(dāng)前的共識規(guī)則肺樟。比特幣內(nèi)核會通過getnetworkinfo
RPC 來報告這個情況,以及運行-alertnotify
命令逻淌,如果有設(shè)置的話么伯。
不論哪種情況,如果區(qū)塊恍风,交易數(shù)據(jù)明顯來自一個沒有使用當(dāng)前共識協(xié)議的節(jié)點蹦狂,區(qū)塊,交易數(shù)據(jù)就不應(yīng)該被轉(zhuǎn)發(fā)朋贬。
SPV客戶端會跟全節(jié)點鏈接起來,通過鏈接多個全節(jié)點窜骄,同時保證這些全節(jié)點在同一區(qū)塊鏈的同一個區(qū)塊高度锦募,考慮到交易延遲,陳腐區(qū)塊邻遏,可加或減掉幾個區(qū)塊糠亩,就可以檢測可能的硬分叉虐骑。如果有分叉,SPV客戶端可以斷掉那些在更弱鏈上節(jié)點間的連接赎线。
SPV客戶端也應(yīng)監(jiān)控區(qū)塊廷没,交易版本號的增加,這樣可以保證SPV客戶端去處理接收到的交易垂寥,并使用新的共識規(guī)則創(chuàng)建新的交易颠黎。
聲明:
文中帶有[?]的地方,表示我對此翻譯明顯感覺不太對的滞项,后續(xù)會不斷修正狭归。
初次翻譯,可能會有些地方翻譯的不好文判,不地道过椎,甚至錯誤,如果有發(fā)現(xiàn)戏仓,還請留言疚宇,指出,以便我好修正赏殃,謝謝灰嫉!