Bitcoin-Core

我究竟如何解碼 leveldb 中的塊文件資訊?

  • June 11, 2019

基於連結 <https://github.com/bitcoin/bitcoin/blob/fcbc8bfa6d10cac4f16699d6e6e68fb6eb98acd0/src/main.h#L392>和 區塊鏈 levelDB 中使用的鍵是什麼(即鍵:值對是什麼)? 我應該簡單地將結果作為變數讀取。所以我寫了一些如下所示的 Python 程式碼。但是我沒有得到我預期的結果。

下面是我用文件號解碼文件資訊的程式碼0。我通過我的解析blk00000.dat發現第一個塊是創世塊,最後一個塊是177帶有 blockhash的塊00000000480c9799dd2b35009ff1833f69690f76c26a9bea7e00cd0042f67db1

nBlocks``134看起來塊是正確的,這是我在blk00000.dat. nHeightFirst看起來值是正確的0,但我nHeightLast不是177nSize並且nUndoSize看起來不正確,因為它與我在終端上找到的文件大小不匹配

ls -l  ~/.bitcoin/blocks/blk00000.dat

ls -l  ~/.bitcoin/blocks/rev00000.dat

此外nTimeFirst,與創世塊的時間戳不匹配。並且nTimeLast與 block 的時間戳不匹配177,我發現它是blk00000.dat. 做錯了什麼?

import plyvel
blockIndexDB = plyvel.DB('/home/chris/.bitcoin/blocks/index')
result = blockIndexDB.get(b'f\x00\x00\x00\x00')

# result value from leveldb
# result = b'\x86\xa8%\xbe\xfe\xf4E\x88\xa5\xa7}\x00\x86\xa8r\x83\xc9\xfd\xd5)\x83\xec\xd3\xa1N'
# hexString = b'86a825befef44588a5a77d0086a87283c9fdd52983ecd3a14e'

nBlocks = int.from_bytes(result[0:1], byteorder='little')
print('nBlocks', nBlocks)
print(nBlocks == 134)

s = int.from_bytes(result[1:2], byteorder='little')
# print('s', s)
nSize = int.from_bytes(result[2:6], byteorder='little')
print('nSize', nSize)
print(nSize == 134216389) # blk00000.dat file size

s = int.from_bytes(result[6:7], byteorder='little')
# print('s', s)
nUndoSize = int.from_bytes(result[7:11], byteorder='little')
print('nUndoSize', nUndoSize)
print(nUndoSize == 19502205) # rev00000.dat file size

nHeightFirst = int.from_bytes(result[11:12], byteorder='little')
print('nHeightFirst', nHeightFirst)
print(nHeightFirst == 0)
nHeightLast = int.from_bytes(result[12:13], byteorder='little')
print('nHeightLast', nHeightLast)
print(nHeightLast == 177)

s = int.from_bytes(result[15:16], byteorder='little')
# print('s', s)
nTimeFirst = int.from_bytes(result[16:20], byteorder='little')
print('nTimeFirst', nTimeFirst)
print(nTimeFirst == 1231006505) # block 0 timestamp

s = int.from_bytes(result[20:21], byteorder='little')
# print('s', s)
nTimeLast = int.from_bytes(result[21:], byteorder='little')
print('nTimeLast', nTimeLast)
# block 177 is the last block in blk00000.dat file
print(nTimeLast == 1231736557) # block 177 timestamp

您將每個值反序列化為整數,但這是不正確的。這些值被序列化為可變長度整數,其中高位表示整數的長度,這些整數被丟棄為實際整數值本身。因此,您需要修復程式碼以將字節反序列化為 varint,而不僅僅是具有固定長度的整數。

以下程式碼能夠正確反序列化條目。

#! /usr/bin/env python3

import binascii

def get_max(long=False):
   if long:
       return 18446744073709551615
   else:
       return 4294967295

def read_var_int(s, pos, long=False):
   n = 0
   while True:
       chData = s[pos]
       pos += 1
       if n &gt; (get_max(long) &gt;&gt; 7):
           raise IOError("ReadVarInt(): size too large");
       n = (n &lt;&lt; 7) | (chData & 0x7F)
       if chData & 0x80:
           if n == get_max(long):
               raise IOError("ReadVarInt(): size too large");
           n += 1
       else:
           return n, pos

entry = binascii.unhexlify(b'86a825befef44588a5a77d0086a87283c9fdd52983ecd3a14e')
pos = 0

nBlocks, pos = read_var_int(entry, pos)
print('nBlocks: {}'.format(nBlocks))
nSize, pos = read_var_int(entry, pos)
print('nSize: {}'.format(nSize))
nUndoSize, pos = read_var_int(entry, pos)
print('nUndoSize: {}'.format(nUndoSize))
nHeightFirst, pos = read_var_int(entry, pos)
print('nHeightFirst: {}'.format(nHeightFirst))
nHeightLast, pos = read_var_int(entry, pos)
print('nHeightLast: {}'.format(nHeightLast))
nTimeFirst, pos = read_var_int(entry, pos)
print('nTimeFirst: {}'.format(nTimeFirst))
nTimeLast, pos = read_var_int(entry, pos)
print('nTimeLast: {}'.format(nTimeLast))

結果是:

nBlocks: 119973
nSize: 134216389
nUndoSize: 19502205
nHeightFirst: 0
nHeightLast: 120050
nTimeFirst: 1231006505
nTimeLast: 1303712078

nBlocks和是預期的nHeightLast,因為早期的塊非常小,但塊文件相當大。我認為您對塊文件中 134 個塊的計算是錯誤的。對於 134 個塊,這些塊的大小必須超過 1 MB,這對於早期塊來說是不正確的。

引用自:https://bitcoin.stackexchange.com/questions/88288