Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
241 lines (194 sloc) 7.55 KB
#
# Code for dumping a single block, given its ID (hash)
#
from bsddb.db import *
import logging
import os.path
import re
import sys
import time
from BCDataStream import *
from base58 import public_key_to_bc_address
from util import short_hex, long_hex
from deserialize import *
def _open_blkindex(db_env):
db = DB(db_env)
try:
r = db.open("blkindex.dat", "main", DB_BTREE, DB_THREAD|DB_RDONLY)
except DBError:
r = True
if r is not None:
logging.error("Couldn't open blkindex.dat/main. Try quitting any running Bitcoin apps.")
sys.exit(1)
return db
def _read_CDiskTxPos(stream):
n_file = stream.read_uint32()
n_block_pos = stream.read_uint32()
n_tx_pos = stream.read_uint32()
return (n_file, n_block_pos, n_tx_pos)
def _dump_block(datadir, nFile, nBlockPos, hash256, hashNext, do_print=True):
blockfile = open(os.path.join(datadir, "blk%04d.dat"%(nFile,)), "rb")
ds = BCDataStream()
ds.map_file(blockfile, nBlockPos)
d = parse_Block(ds)
block_string = deserialize_Block(d)
ds.close_file()
blockfile.close()
if do_print:
print "BLOCK "+long_hex(hash256[::-1])
print "Next block: "+long_hex(hashNext[::-1])
print block_string
return block_string
def _parse_block_index(vds):
d = {}
d['version'] = vds.read_int32()
d['hashNext'] = vds.read_bytes(32)
d['nFile'] = vds.read_uint32()
d['nBlockPos'] = vds.read_uint32()
d['nHeight'] = vds.read_int32()
header_start = vds.read_cursor
d['b_version'] = vds.read_int32()
d['hashPrev'] = vds.read_bytes(32)
d['hashMerkle'] = vds.read_bytes(32)
d['nTime'] = vds.read_int32()
d['nBits'] = vds.read_int32()
d['nNonce'] = vds.read_int32()
header_end = vds.read_cursor
d['__header__'] = vds.input[header_start:header_end]
return d
def dump_block(datadir, db_env, block_hash):
""" Dump a block, given hexadecimal hash-- either the full hash
OR a short_hex version of the it.
"""
db = _open_blkindex(db_env)
kds = BCDataStream()
vds = BCDataStream()
n_blockindex = 0
key_prefix = "\x0ablockindex"
cursor = db.cursor()
(key, value) = cursor.set_range(key_prefix)
while key.startswith(key_prefix):
kds.clear(); kds.write(key)
vds.clear(); vds.write(value)
type = kds.read_string()
hash256 = kds.read_bytes(32)
hash_hex = long_hex(hash256[::-1])
block_data = _parse_block_index(vds)
if (hash_hex.startswith(block_hash) or short_hex(hash256[::-1]).startswith(block_hash)):
print "Block height: "+str(block_data['nHeight'])
_dump_block(datadir, block_data['nFile'], block_data['nBlockPos'], hash256, block_data['hashNext'])
(key, value) = cursor.next()
db.close()
def read_block(db_cursor, hash):
(key,value) = db_cursor.set_range("\x0ablockindex"+hash)
vds = BCDataStream()
vds.clear(); vds.write(value)
block_data = _parse_block_index(vds)
block_data['hash256'] = hash
return block_data
def scan_blocks(datadir, db_env, callback_fn):
""" Scan through blocks, from last through genesis block,
calling callback_fn(block_data) for each.
callback_fn should return False if scanning should
stop, True if it should continue.
Returns last block_data scanned.
"""
db = _open_blkindex(db_env)
kds = BCDataStream()
vds = BCDataStream()
# Read the hashBestChain record:
cursor = db.cursor()
(key, value) = cursor.set_range("\x0dhashBestChain")
vds.write(value)
hashBestChain = vds.read_bytes(32)
block_data = read_block(cursor, hashBestChain)
while callback_fn(block_data):
if block_data['nHeight'] == 0:
break;
block_data = read_block(cursor, block_data['hashPrev'])
return block_data
def dump_block_n(datadir, db_env, block_number):
""" Dump a block given block number (== height, genesis block is 0)
"""
def scan_callback(block_data):
return not block_data['nHeight'] == block_number
block_data = scan_blocks(datadir, db_env, scan_callback)
print "Block height: "+str(block_data['nHeight'])
_dump_block(datadir, block_data['nFile'], block_data['nBlockPos'], block_data['hash256'], block_data['hashNext'])
def search_blocks(datadir, db_env, pattern):
""" Dump a block given block number (== height, genesis block is 0)
"""
db = _open_blkindex(db_env)
kds = BCDataStream()
vds = BCDataStream()
# Read the hashBestChain record:
cursor = db.cursor()
(key, value) = cursor.set_range("\x0dhashBestChain")
vds.write(value)
hashBestChain = vds.read_bytes(32)
block_data = read_block(cursor, hashBestChain)
if pattern == "NONSTANDARD_CSCRIPTS": # Hack to look for non-standard transactions
search_odd_scripts(datadir, cursor, block_data)
return
while True:
block_string = _dump_block(datadir, block_data['nFile'], block_data['nBlockPos'],
block_data['hash256'], block_data['hashNext'], False)
if re.search(pattern, block_string) is not None:
print "MATCH: Block height: "+str(block_data['nHeight'])
print block_string
if block_data['nHeight'] == 0:
break
block_data = read_block(cursor, block_data['hashPrev'])
def search_odd_scripts(datadir, cursor, block_data):
""" Look for non-standard transactions """
while True:
block_string = _dump_block(datadir, block_data['nFile'], block_data['nBlockPos'],
block_data['hash256'], block_data['hashNext'], False)
found_nonstandard = False
for m in re.finditer(r'TxIn:(.*?)$', block_string, re.MULTILINE):
s = m.group(1)
if re.match(r'\s*COIN GENERATED coinbase:\w+$', s): continue
if re.match(r'.*sig: \d+:\w+...\w+ \d+:\w+...\w+$', s): continue
if re.match(r'.*sig: \d+:\w+...\w+$', s): continue
print "Nonstandard TxIn: "+s
found_nonstandard = True
break
for m in re.finditer(r'TxOut:(.*?)$', block_string, re.MULTILINE):
s = m.group(1)
if re.match(r'.*Script: DUP HASH160 \d+:\w+...\w+ EQUALVERIFY CHECKSIG$', s): continue
if re.match(r'.*Script: \d+:\w+...\w+ CHECKSIG$', s): continue
print "Nonstandard TxOut: "+s
found_nonstandard = True
break
if found_nonstandard:
print "NONSTANDARD TXN: Block height: "+str(block_data['nHeight'])
print block_string
if block_data['nHeight'] == 0:
break
block_data = read_block(cursor, block_data['hashPrev'])
def check_block_chain(db_env):
""" Make sure hashPrev/hashNext pointers are consistent through block chain """
db = _open_blkindex(db_env)
kds = BCDataStream()
vds = BCDataStream()
# Read the hashBestChain record:
cursor = db.cursor()
(key, value) = cursor.set_range("\x0dhashBestChain")
vds.write(value)
hashBestChain = vds.read_bytes(32)
back_blocks = []
block_data = read_block(cursor, hashBestChain)
while block_data['nHeight'] > 0:
back_blocks.append( (block_data['nHeight'], block_data['hashMerkle'], block_data['hashPrev'], block_data['hashNext']) )
block_data = read_block(cursor, block_data['hashPrev'])
back_blocks.append( (block_data['nHeight'], block_data['hashMerkle'], block_data['hashPrev'], block_data['hashNext']) )
genesis_block = block_data
print("check block chain: genesis block merkle hash is: %s"%(block_data['hashMerkle'][::-1].encode('hex_codec')))
while block_data['hashNext'] != ('\0'*32):
forward = (block_data['nHeight'], block_data['hashMerkle'], block_data['hashPrev'], block_data['hashNext'])
back = back_blocks.pop()
if forward != back:
print("Forward/back block mismatch at height %d!"%(block_data['nHeight'],))
print(" Forward: "+str(forward))
print(" Back: "+str(back))
block_data = read_block(cursor, block_data['hashNext'])