如果你對比特幣交易等數據感興趣的話,可以自己部署一個BitcoinCore的全節點來同步數據
推薦京東的bds-btc,它已經修改了源碼可以將區塊的raw_data 發送到kafka中,然後能夠從kafka中取消費它
https://github.com/jdcloud-bds/bds-btc
這裏我主要解析下比特幣的區塊數據是怎麼樣的
區塊整體結構
一個完整的區塊結構主要由以下幾部分構成:
字節 | 字段 | 說明 |
---|---|---|
4 | 區塊大小 | 用字節表示的該字段之後的區塊大小 |
80 | 區塊頭 | 組成區塊頭的幾個字段 |
1-9 | 交易計數器 | 該區塊包含的交易數量,包含coinbase交易 |
不定 | 交易 | 記錄在區塊裏的交易信息,使用原生的交易信息格式,並且交易在數據流中的位置必須與Merkle樹的葉子節點順序一致 |
區塊頭結構
字節 | 字段 | 說明 |
---|---|---|
4 | 版本 | 區塊版本號,表示本區塊遵守的驗證規則 |
32 | 父區塊頭哈希值 | 前一區塊的哈希值,使用SHA256(SHA256(父區塊頭))計算 |
32 | Merkle根 | 該區塊中交易的Merkle樹根的哈希值,同樣採用SHA256(SHA256())計算 |
4 | 時間戳 | 該區塊產生的近似時間,精確到秒的UNIX時間戳,必須嚴格大於前11個區塊時間的中值,同時全節點也會拒絕那些超出自己2個小時時間戳的區塊 |
4 | 難度目標 | 該區塊工作量證明算法的難度目標,已經使用特定算法編碼 |
4 | Nonce | 爲了找到滿足難度目標所設定的隨機數,爲了解決32位隨機數在算力飛昇的情況下不夠用的問題,規定時間戳和coinbase交易信息均可更改,以此擴展nonce的位數 |
區塊頭(80字節):
0100000055bd840a78798ad0da853f68974f3d183e2bd1db6a842c1feecf222a00000000ff104ccb05421ab93e63f8c3ce5c2c2e9dbb37de2764b3a3175c8166562cac7d51b96a49ffff001d283e9e70
版本號(4字節):01000000
父區塊頭hash值(32字節):55bd840a78798ad0da853f68974f3d183e2bd1db6a842c1feecf222a00000000
merkle根(32字節):ff104ccb05421ab93e63f8c3ce5c2c2e9dbb37de2764b3a3175c8166562cac7d
時間戳(4字節):51b96a49
難度(4字節):ffff001d
Nonce(4字節):283e9e70
代碼實現:
class block():
def __init__(self, handle):
if type(handle)==str: handle=fstring(handle)
self.magic = handle.read(4)
self.size = sum([ord(handle.read(1))*(256**x) for x in range(4)])
startingpos = handle.tell()
self.version = sum([ord(handle.read(1))*(256**x) for x in range(4)])
self.prevblock = handle.read(32)[::-1].encode('hex')
self.merkleroot = handle.read(32)[::-1].encode('hex')
self.timestamp = time.gmtime(sum([ord(handle.read(1))*(256**x) for x in range(4)]))
self.bits = handle.read(4)
self.nonce = sum([ord(handle.read(1))*(256**x) for x in range(4)])
handle.seek(startingpos)
self.header = handle.read(80)
self.hash = hash256(self.header)[::-1].encode('hex')
self.txcount = ord(handle.read(1))
if self.txcount>=253: self.txcount = sum([ord(handle.read(1))*(256**x) for x in range(2*(self.txcount-252))])
self.tx = [transaction(handle) for txn in range(self.txcount)]
self.size = handle.tell() - startingpos; handle.seek(startingpos)
self.raw = handle.read(self.size)
#self.merkletree
#self.isvalid() to verify merkle tree, hash, and difficulty
交易同理,只要掌握了它的數據結構解析出來就很簡單了,只是表示形式不同而已,這裏可以參考:
https://www.jianshu.com/p/8289df50112f
解析交易代碼實現:
class transaction():
def __init__(self, handle):
if type(handle)==str: handle=fstring(handle)
startingpos = handle.tell()
self.version = sum([ord(handle.read(1))*(256**x) for x in range(4)])
self.numinputs = ord(handle.read(1))
if self.numinputs>=253: self.numinputs = sum([ord(handle.read(1))*(256**x) for x in range(2*(self.numinputs-252))])
self.inputs = [txinput(handle) for inputnum in range(self.numinputs)]
self.numoutputs = ord(handle.read(1))
if self.numoutputs>=253: self.numoutputs = sum([ord(handle.read(1))*(256**x) for x in range(2*(self.numoutputs-252))])
self.outputs = [txoutput(handle) for outputnum in range(self.numoutputs)]
self.locktime = sum([ord(handle.read(1))*(256**x) for x in range(4)])
self.size = handle.tell() - startingpos; handle.seek(startingpos)
self.raw = handle.read(self.size)
self.hash = hash256(self.raw)[::-1].encode('hex')
以上是比較原始的方法,你可以藉助其他工具,我這裏總結了一些,希望對你有用;
(1)本地rpc的方法:
https://www.jianshu.com/p/514512224e68
bitcoind -damon
bitcoin-cli -rpcconnect=127.0.0.1 -rpcuser=rpc -rpcpassword=123 getblock 00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048
(2) 直接讀取
瞭解區塊數據結構即可,參考 https://github.com/rigmarole/blk-reader
(3) 借用工具
https://github.com/alecalve/python-bitcoin-blockchain-parser
(4) 藉助API
https://github.com/blockchain/api-v1-client-python
(5) 其他
一個好用的工具bitiodine:
https://github.com/mikispag/bitiodine
bitcoin數據分析:
https://github.com/citp/BlockSci
因爲數據量比較大,可以結合一些spark等工具來進行解析和分析,如果要用於交易溯源等可以參考一些論文。如果你對比特幣或者其他區塊鏈數據分析感興趣可以私信可以進行一起研究,謝謝,鳴謝此前作出解讀比特幣數據結構的同學。