天天看點

《區塊鍊開發指南》一一1.3 挖礦、礦池

本節書摘來自華章計算機《區塊鍊開發指南》一書中的第1章,第1.3節,作者:申屠青春 主編 宋 波 張 鵬 汪曉明 季宙棟 左川民 編著更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

1.3.1 挖礦原理與區塊的産生

比特币的挖礦和節點軟體是基于對等網絡、數字簽名來發起和驗證交易的。節點向網絡廣播交易,這些廣播出來的交易需要經過礦工的驗證,礦工們會用自己的工作證明結果來表達确認,确認後的交易會被打包到資料塊中,資料塊會串起來形成連續的資料塊鍊。中本聰本人設計了第一版的比特币挖礦程式,這一程式随後被開發為廣泛使用的第一代挖礦軟體bitcoind,這一代軟體在2009年到2010年期間都比較流行。

每一個比特币的節點都會收集所有尚未确認的交易,并且會将其歸集到一個資料塊中,這個資料塊将和前面一個資料塊內建在一起。礦工節點會附加一個随機調整數,并計算前一個資料塊的sha-256 hash運算值。挖礦節點不斷進行重複嘗試,直到它找到的随機調整數使得産生的hash值低于某個特定的目标為止。由于hash運算是不可逆的,是以尋找到符合要求的随機調整數将會非常困難,是以需要一個可以預計總次數的不斷試錯的過程。這時,工作量證明機制就發揮作用了。當一個節點找到了符合要求的解,那麼它就可以向全網廣播自己的結果。其他節點就可以接收這個新解出來的資料塊,并檢驗其是否符合規則。隻要其他節點通過計算hash值發現其确實滿足要求(比特币要求的運算目标),那麼該資料塊就是有效的,其他的節點就會接受該資料塊,并将其附加在自己已有的鍊條之後。

當挖礦時,你會經常對區塊頭進行散列,你正在挖的區塊也會時常進行更新,一個區塊頭如上文所述的表1-3所示。

表1-3中的大部分資料項對所有使用者都是一緻的,不過,在時間戳上可能會有些差別。如果目前區塊的時間戳大于前11個區塊的平均時間戳,并且小于“網絡調整時間(network-adjusted time)”+ 2小時,則認為該時間戳是有效的。其中的“網絡調整時間”是指與你相連接配接的所有節點的平均時間。當節點a連接配接到節點b時,a将從b處得到一個utc的時間戳,a先将其轉換成本地utc并儲存起來,網絡調整時間等于所有節點的本地utc時間+所有相連節點的偏移量平均值,然而,該網絡時間永遠不會調整到超過本地系統時間70分鐘以上。

nonce随機數通常都不會相同,但是它以嚴格的線性方式在增長,從0開始,每次執行散列時都會增長,當nonce溢出時(此事經常發生),挖礦交易的extranonce項就會增長,其将改變merkle樹的根節點。

假定針對這些資料項,人們經常會獨自産生同樣序列号的hash值,那麼,最快的礦機通常會赢。然而,兩人産生同樣的merkle根節點基本上(或幾乎)是不可能的,因為區塊中的第一個交易是挖礦交易并且會“發送”到你獨一無二的比特币位址上。而你的區塊與其他人的區塊是有差別的,是以,産生的hash值肯定也會(幾乎可以肯定)不同,你計算的每個hash值和網絡中的其他人一樣,都有同樣的獲勝機會。

比特币使用sha256(sha256(區塊頭))計算hash值,但要注意位元組序。例如,以下的python代碼用于計算某一區塊的hash值,使用的是2011年6月區塊号為125552的最小hash值。該區塊頭建立在表1-3所示的6個資料項之上,并且以十六進制的小端結尾方式連接配接在一起。

實際的hash值是一串256位的數值,首部有許多零。當以大頭端十六進制常數方式列印或存儲時,它的首部有許多零;如果它以小頭端列印或存儲時,零就會變換到尾部。例如,如果表示成位元組串-最低(或者開頭)的位元組串位址顯示最小位的數,那麼這就是小頭端表示。blockexplorer的輸出把hash值顯示為大頭端表示的數值,因為數字的表示通常是首部數字是最大的數字(從左向右讀)。

1.3.2 挖礦難度

挖礦難度是對挖礦困難程度的度量,即指計算符合給定目标的一個hash值的困難程度。比特币網絡有一個全局的區塊難度,有效的區域必須有一個hash值,該hash值必須小于給定的目标hash值。礦池也會有一個自定義的共享難度,用來設定産生股份的最低難度限制。

難度每過2016塊就會改變一次,計算公式為:

difficulty = difficulty_1_target/current_target

其中,目标(target)是一個256位長的數值。

測量難度有許多不同的方法,通過這些方法得到的diff?iculty_1_target有可能也會不同。傳統情況下,它表示一個hash值,前32位為0,後續部分為1(稱之為礦池難度或pdiff),比特币協定把目标hash值表示成一個固定精度的自定義浮點類型,因而,比特币用戶端用該值來估計難度(稱之為bdiff)。

難度經常被存儲在區塊中,每個塊存儲一個十六制的目标hash值的壓縮表達式(稱之為bits),目标hash值可以通過預先定義的公式計算出來。例如:如果區塊中壓縮的目标hash值為0x1b0404cb,那麼十六進制的目标hash值就為如下形式:

因而目标hash值為0x1b0404cb時,難度為:

或者:

其中:0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff是挖礦機使用的最大目标hash值。而0x00000000ffff00000000000000000000000000000

00000000000000000000000則是比特币網絡使用的浮點編碼類型,後面的位數被縮短了。

下面是一個快速計算比特币難度的方法,這裡使用的算法是修改的泰勒序列(讀者可以參考wikipedia上的教程),并且依賴記錄來轉換難度計算。

如果想要了解難度計算的數學原理,那麼可以看看如下的python代碼:

最大難度大約等于maximum_target/1(因為0會導緻無窮大),這是一個非常大的數值,大約為2224;當maximum_target為最小值1時,則最小難度值也為1。

難度可根據以前2016個區塊的産生時間而定,每過2016塊就會改變一次。預計每隔10分鐘産生一個區塊,因而産生2016個區塊要花費2周時間。如果前2016個區塊的産生時間多于兩周,則難度會降低;否則難度就會增加。

為了找到新區塊,該區塊的hash值必須小于目标hash值,實際上它是一個在0到2256-1之間的随機數,難度1的偏移量是:

0xffff×2208

難度d的偏移量是:

(0xffff×2208)/d

在難度d下,為了找到新區塊,預期要計算的hash數量是:

d×2256/(0xffff×2208)

或者隻是:

d×248/0xffff

難度的設定,是為了以每10分鐘一個區塊的速度産生2016個區塊,因而,在600秒内計算(d×248/0xffff)個hash,這就意味着産生2016個區塊的網絡hash速率(算力)是:

d×248/0xffff/600

可以進一步簡化為:

d×232/600

以上公式有較好的精度。

在難度為1時,算力是7mhashes/秒,難度是5?006?860?589,這就意味着以前2016個區塊被找到,其平均算力是:35.840phash/s。

5?006?860?589×232/600≈35.840 phash/s

發現一個區塊的平均時間,可以用以下公式估計:

時間=難度×232/算力

其中,難度是目前的難度,算力是指礦機的計算能力,以hashes/s為機關,時間是你找到兩個區塊的平均時間。舉例來說,使用python計算,算力為1ghashes/s的礦機,難度在20?000時,産生一個新區塊的時間,計算式如下:

$ python -c "print 20000 * 232 / 109 / 60 / 60.0"

23.85

其中**表示指數,該語句運算的結果就是:找到一個新區塊要花費近1天的時間。

1.3.3 礦池原理與商業模式

随着生成區塊的難度逐漸增加,挖礦變成了一個碰運氣的事情,單一節點要生成一個區塊需要花費數年的時間(除非這個單一節點擁有大量的計算力)。為了激勵計算力較低的使用者繼續參與挖礦,礦池就出現了。在一個礦池裡,許多不同的人貢獻出自己的計算力來生成一個區塊,然後再根據每個人的貢獻比例來分發獎勵。通過這種方式,要得到那個50個比特币的獎勵就不必等待數年的時間了,小礦工能定期得到屬于他們那部分的比特币獎勵。一個share(貢獻/股份)為一個礦池給用戶端的一個合法的工作證明,同時這也是用來生成區塊的工作證明,但是沒有這麼複雜,隻需要很少的時間就能達到一個share。

礦池是比特币(bitcoin)等p2p密碼學虛拟貨币開采所必需的基礎設施,一般是對外開放的團隊開采伺服器。其存在的意義是提升比特币開采的穩定性,使礦工薪酬趨于穩定,目前國内較為著名的比特币商業礦池有f2pool、btcc pool、bw pool、btc.com等。

關于礦池挖礦的方式,目前存在如下幾種不同的方式。

slush方式:slush礦池基于積分制,較老的shares将比新的shares擁有更低的權重,以減少一輪中切換礦池的投機分子。

pay-per-share方式:該方式為立即為每一個share支付報酬。該支出來源于礦池現有的比特币資金,是以可以立即取現,而不用等待區塊生成完畢或确認之後。這樣可以避免礦池營運者幕後操縱。這種方法減少了礦工的風險,但将風險轉移給了礦池的營運者。營運者可以收取手續費來彌補這些風險可能造成的損失。

luke-jr方式:該方式借用了其他方式的長處,如slush方式一樣,礦工需要提供工作證明來獲得shares,如puddinpop方式一樣,當區塊生成時馬上進行支付。但是不像之前的方式,一個區塊的shares,會被再次利用來生成下一個區塊。為了區分參與礦工的交易傳輸費用,隻有當礦工的餘額超過1btc時才進行支付。如果沒有達到1btc,那麼将在下一個區塊生成時進行累計。如果礦工在一周内沒有提供一個share,那麼礦池會将剩下的餘額進行支付,不管餘額是多少。

triplemining方式:該方式是将一些中等大小礦池的計算力合并起來,然後将獲得獎勵的1%按照各個礦池計算力的比例分發給礦池營運者。

p2pool方式:p2pool的挖礦節點工作在類似于比特币區塊鍊的一種shares鍊上。由于沒有中心,是以也不會受到dos攻擊。和其他現有的礦池技術都不一樣,在該方式下,每個節點工作的區塊,都包括支付給前期shares的所有者及該節點自己的比特币。99%的獎勵(50btc +交易費用)會平均配置設定給礦工,另外0.5%會獎勵給生成區塊的人。

puddinpop方式:一種使用“元哈希”技術的方式,使用特定的puddinpop挖礦軟體,現在已經沒有礦池使用這種方式了。

目前使用較多的方式為pay-per-share(pps),礦工使用起來也比較友善。

但從去中心化的角度來說,還是推薦p2pool,在避免dos攻擊的同時,也能防止個别礦池擁有超大的計算力而對比特币網絡造成威脅。不過p2pool的使用方式較pps更為複雜。

繼續閱讀