簡(jiǎn)單回顧下挖礦的流程捺球。
首先先要對(duì)所有的交易做驗(yàn)證,剔除有問(wèn)題的班巩,然后通過(guò)一套自定義的標(biāo)準(zhǔn)來(lái)選擇哪些交易希望打包進(jìn)區(qū)塊渣慕,比如說(shuō)提供的交易費(fèi)與交易占用的字節(jié)大小的比值超過(guò)某個(gè)門(mén)檻,這樣的交易才被認(rèn)為有利可圖抱慌。當(dāng)然逊桦,節(jié)點(diǎn)也可以特意選擇要加入某條交易,或者故意忽略某些交易抑进。如果是通過(guò)礦池挖礦的話(huà)强经,礦池的服務(wù)器會(huì)去篩選交易,然后分配給每個(gè)參與的礦機(jī)一個(gè)獨(dú)立的任務(wù)寺渗。
一旦篩選好交易數(shù)據(jù)匿情,層層約減,通過(guò)這些交易就可以計(jì)算出一棵Merkle樹(shù)信殊,可以確定一個(gè)唯一的摘要炬称,這就是Merkl樹(shù)的根。
然后我們?cè)僖来潍@取挖礦需要的其他信息涡拘,這些信息組成一個(gè)區(qū)塊的頭玲躯。
區(qū)塊頭的字節(jié)分配
- version 版本號(hào),4個(gè)字節(jié)
- previous_block_hash 前一區(qū)塊的摘要,32個(gè)字節(jié)
- merkle_root 默克爾樹(shù)的根跷车,32個(gè)字節(jié)
- time 區(qū)塊生成時(shí)間棘利,4個(gè)字節(jié)
- bits 難度目標(biāo),是一個(gè)數(shù)字朽缴,4個(gè)字節(jié)
- nonce 隨機(jī)數(shù)善玫,4個(gè)字節(jié)
區(qū)塊頭只有80個(gè)字節(jié),挖礦只需要對(duì)區(qū)塊頭進(jìn)行運(yùn)算即可不铆。交易數(shù)據(jù)都通過(guò)merkle樹(shù)固定了下來(lái)蝌焚,不需要再包含進(jìn)來(lái)。
這些信息中大部分已經(jīng)是固定下來(lái)的誓斥,或者是可計(jì)算的。
- 版本號(hào)是跟隨比特幣客戶(hù)端而定的许帐,一段時(shí)間內(nèi)不會(huì)改變劳坑。即使要改變,也會(huì)有比特幣的核心開(kāi)發(fā)人員來(lái)協(xié)調(diào)升級(jí)策略成畦,這個(gè)可以理解為一個(gè)靜態(tài)常數(shù)距芬。
- 前一區(qū)塊的摘要,可以通過(guò)數(shù)學(xué)方法快速計(jì)算循帐,因?yàn)榍耙粎^(qū)塊早已打包好了框仔。
- 默克爾樹(shù)的根,剛才已經(jīng)得到了結(jié)果拄养。
- 時(shí)間离斩,可以取打包時(shí)的時(shí)間,也不需要很精確瘪匿,前后幾秒跛梗,幾十秒也都可以。
- 難度目標(biāo)棋弥,是參考上兩周產(chǎn)生的區(qū)塊的平均生成時(shí)間而定的核偿,兩周內(nèi)如果平均10分鐘產(chǎn)生一個(gè)區(qū)塊的話(huà),兩周會(huì)產(chǎn)生2016個(gè)區(qū)塊顽染,軟件會(huì)計(jì)算最新的2016個(gè)區(qū)塊生成的時(shí)間漾岳,然后做對(duì)比,隨之調(diào)整難度粉寞,使得接下來(lái)產(chǎn)生的區(qū)塊的預(yù)期時(shí)間保持在10分鐘左右尼荆。因?yàn)樽罱?016個(gè)區(qū)塊已經(jīng)確定,所以這個(gè)數(shù)字也是確定的仁锯。
- 最后一個(gè)隨機(jī)數(shù)耀找,就是挖礦的目標(biāo)了。這個(gè)數(shù)字可以變化,而且要從0試到最大值野芒。直到最后出現(xiàn)的hash結(jié)果蓄愁,其數(shù)字必須低于難度目標(biāo)值。不過(guò)以現(xiàn)在的計(jì)算機(jī)算力狞悲,這個(gè)數(shù)字用不了一秒就把全部的變化可能計(jì)算完了撮抓,所以還需要改變區(qū)塊內(nèi)部的創(chuàng)幣交易中的附帶消息,這樣就讓merkle root也發(fā)生了變化摇锋,從而有更多的可能去找到符合要求的nonce丹拯。
我們以區(qū)塊277316為例,其信息來(lái)自網(wǎng)站http://blockchain.info
Bitcoin Block #277316blockchain.info
選擇這個(gè)區(qū)塊的原因是在《Mastering Bitcoin》一書(shū)中荸恕,中文社區(qū)譯本和英文原版在介紹這部分內(nèi)容時(shí)有出入乖酬,而且作者Antonopoulos并沒(méi)有提到一個(gè)關(guān)鍵點(diǎn),就是字節(jié)順序的問(wèn)題融求,相信很多人可能會(huì)踩這個(gè)坑咬像。這里還原的細(xì)節(jié)可以幫助讀者與書(shū)籍做相互參考。
請(qǐng)大家注意下面的每個(gè)步驟生宛,注意每一個(gè)變化县昂,這是比特幣最核心的算法。
第一步陷舅,準(zhǔn)備數(shù)據(jù)倒彰,轉(zhuǎn)換時(shí)間
2 (版本號(hào)的十進(jìn)制)
0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569 (前一區(qū)塊hash值的16進(jìn)制)
c91c008c26e50763e9f548bb8b2fc323735f73577effbc55502c51eb4cc7cf2e (merkle root的16進(jìn)制)
2013-12-27 23:11:54 (utc時(shí)間)
419668748 (難度目標(biāo)的十進(jìn)制)
924591752 (隨機(jī)數(shù)的十進(jìn)制)
轉(zhuǎn)換時(shí)間,記住莱睁,一定要轉(zhuǎn)為utc的時(shí)間戳待讳,此處遇到過(guò)坑,小心缩赛。
>>> import datetime
>>> from datetime import timezone
>>> datetime.datetime.strptime('2013-12-27 23:11:54', '%Y-%m-%d %H:%M:%S').replace(tzinfo=timezone.utc).timestamp()
1388185914.0
第二步耙箍,全部轉(zhuǎn)換為16進(jìn)制
00000002
0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569
c91c008c26e50763e9f548bb8b2fc323735f73577effbc55502c51eb4cc7cf2e
52be093a
1903a30c
371c2688
第三步,從big-endian轉(zhuǎn)化為little-endian
這一步的發(fā)現(xiàn)異常艱辛酥馍,耗費(fèi)了大量的查詢(xún)辩昆,大坑,大坑旨袒,謹(jǐn)記汁针。發(fā)明人中本聰可能為了讓機(jī)器計(jì)算更快,而變?yōu)榱烁咏鼨C(jī)器的編碼方式little-endian.
02000000
69054f28012b4474caa9e821102655cc74037c415ad2bba70200000000000000
2ecfc74ceb512c5055bcff7e57735f7323c32f8bbb48f5e96307e5268c001cc9
3a09be52
0ca30319
88261c37
第四步砚尽,拼接字符串施无,開(kāi)始驗(yàn)證
import binascii
from hashlib import sha256 as s
k = '0200000069054f28012b4474caa9e821102655cc74037c415ad2bba702000000000000002ecfc74ceb512c5055bcff7e57735f7323c32f8bbb48f5e96307e5268c001cc93a09be520ca3031988261c37'
hk = binascii.unhexlify(k)
res = binascii.hexlify(s(s(hk).digest()).digest()[::-1])
最終得到的結(jié)果就是
0000000000000001b6b9a13b095e96db41c4a928b97ef2d944a9b31b2cc7bdc4
16進(jìn)制下前面15個(gè)0,然后是1必孤; 而難度目標(biāo)對(duì)應(yīng)的數(shù)字是
0000000000000003a30c00000000000000000000000000000000000000000000
16進(jìn)制下前面15個(gè)0猾骡,然后是3. 計(jì)算結(jié)果小于難度目標(biāo)瑞躺,符合要求。這個(gè)結(jié)果與網(wǎng)站上公布的數(shù)字一致兴想。
在挖礦時(shí)幢哨,nonce隨機(jī)數(shù)是未知的,要從0試到2^32嫂便,但是這個(gè)數(shù)字其實(shí)不大捞镰,只有4294967296,以現(xiàn)在的礦機(jī)動(dòng)輒14T每秒的算力毙替,全部算完到上限也不需要一秒岸售。剛才提到在這種情況下,需要使用創(chuàng)幣交易中的附帶信息厂画,額外的字符串成為extra nonce凸丸。
另外,創(chuàng)世區(qū)塊也可以通過(guò)上面的方法來(lái)驗(yàn)證袱院,有好奇的朋友可以嘗試下甲雅。
提示:
- 對(duì)于創(chuàng)始區(qū)塊,版本號(hào)是1坑填;
- 前一區(qū)塊的hash摘要,猜想會(huì)是什么呢弛姜?
- 難度目標(biāo)是1脐瑰,這是定義為一個(gè)sha256結(jié)果的前32位是0,也就是對(duì)應(yīng)的16進(jìn)制字符串要有8個(gè)0廷臼,那么難度bits此時(shí)是0x1d00ffff苍在。
- 然后再用上面的問(wèn)題的解法去求解隨機(jī)數(shù)就可以了。