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 dump_all_transactions(datadir, db_env): """ Dump all transactions. """ blockfile = open(os.path.join(datadir, "blk%04d.dat"%(1,)), "rb") block_datastream = BCDataStream() block_datastream.map_file(blockfile, 0) def for_each_block(block_data): block_datastream.seek_file(block_data['nBlockPos']) data = parse_Block(block_datastream) block_datetime = datetime.fromtimestamp(data['nTime']) dt = "%d-%02d-%02d-%02d-%02d-%02d"%(block_datetime.year, block_datetime.month, block_datetime.day, block_datetime.hour, block_datetime.minute, block_datetime.second) for txn in data['transactions']: try: for txIn in txn['txIn']: if txIn['prevout_hash'] == "\x00"*32: print 'in\t' + txn['hash'] + '\tcoinbase\t' + dt else: pk = extract_public_key(txIn['scriptSig']) print 'in\t' + txn['hash'] + '\t' + long_hex(txIn['prevout_hash'][::-1]) + '\t' + str(txIn['prevout_n']) + '\t' + pk + '\t' + dt index = 0 for txOut in txn['txOut']: pk = extract_public_key(txOut['scriptPubKey']) print 'out\t' + txn['hash'] + '\t' + str(index) + '\t' + pk + '\t' + str(txOut['value']/1.0e8) + '\t' + dt index += 1 except: pass return True scan_blocks(datadir, db_env, for_each_block) db_env.close()
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 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 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'])
def process_tx(self): hash = self.tx tx_broadcast = dict(hash=hash, value=0); logging.info("processing tx hash: "+hash) template = self.daemon.conn.proxy.getblocktemplate() txns = template["transactions"]; txdata = None for tx in txns: if tx["hash"] == hash: logging.info("tx found in mempool") txdata = tx["data"] break if txdata: raw = BCDataStream() raw.write(txdata.decode('hex_codec')) tx = parse_Transaction(raw) for out in tx["txOut"]: tx_broadcast["value"] += out["value"] else: logging.info("unable to find tx in mempool") try: tx = self.daemon.conn.gettransaction(hash) tx = tx.transaction[0] logging.debug(tx) for out in tx["outpoints"]: tx_broadcast["value"] += long(out["value"]) except bitcoinrpc.exceptions.InvalidAddressOrKey: logging.info("tx not found in blockchain") sys.exit(1) date = datetime.datetime.fromtimestamp(tx["time"]).replace(tzinfo=tzlocal()) tx_broadcast["time"] = date.strftime('%Y-%m-%d %H:%M:%S%z') tx_broadcast["value"] = format(tx_broadcast["value"] / 1e6,'.6f') self.txnotify.post(tx_broadcast)
def _dump_tx(datadir, tx_hash, tx_pos): blockfile = open(os.path.join(datadir, "blk%04d.dat"%(tx_pos[0],)), "rb") ds = BCDataStream() ds.map_file(blockfile, tx_pos[2]) d = parse_Transaction(ds) print deserialize_Transaction(d) ds.close_file() blockfile.close()
def _dump_tx(datadir, tx_hash, tx_pos): BLOCK_HEADER_SIZE = 80 blockfile = open(os.path.join(datadir, "blocks","blk%05d.dat"%(tx_pos[0],)), "rb") ds = BCDataStream() ds.map_file(blockfile, tx_pos[1]+BLOCK_HEADER_SIZE+tx_pos[2]) tx = parse_Transaction(ds) tx['hash'] = tx_hash[::-1] ds.close_file() blockfile.close() return tx
def _dump_block(datadir, nFile, nBlockPos, blkhash): blockfile = open(os.path.join(datadir,"blocks","blk%05d.dat"%(nFile,)), "rb") ds = BCDataStream() ds.map_file(blockfile, nBlockPos) block_start = ds.read_cursor block = parse_Block(ds) block_end = ds.read_cursor block['blk_size'] = (block_end - block_start) ds.close_file() blockfile.close() return block
def main(): import optparse parser = optparse.OptionParser(usage="%prog [options]") parser.add_option("--datadir", dest="datadir", default=None, help="Look for files here (defaults to bitcoin default)") parser.add_option("--regex", dest="lookfor", default="/P2SH/", help="Look for string/regular expression (default: %default)") parser.add_option("--n", dest="howmany", default=999999, type="int", help="Look back this many blocks (default: all)") parser.add_option("--start", dest="start", default=0, type="int", help="Skip this many blocks to start (default: 0)") parser.add_option("--verbose", dest="verbose", default=False, action="store_true", help="Print blocks that match") (options, args) = parser.parse_args() if options.datadir is None: db_dir = determine_db_dir() else: db_dir = options.datadir try: db_env = create_env(db_dir) except DBNoSuchFileError: logging.error("Couldn't open " + db_dir) sys.exit(1) blockfile = open(os.path.join(db_dir, "blk%04d.dat"%(1,)), "rb") block_datastream = BCDataStream() block_datastream.map_file(blockfile, 0) results = defaultdict(int) def count_matches(block_data): block_datastream.seek_file(block_data['nBlockPos']) data = parse_Block(block_datastream) coinbase = data['transactions'][0] scriptSig = coinbase['txIn'][0]['scriptSig'] if results['skipped'] < options.start: results['skipped'] += 1 else: results['checked'] += 1 if re.search(options.lookfor, scriptSig) is not None: results['matched'] += 1 if options.verbose: print("Block %d : %s"%(block_data['nHeight'], scriptSig.encode('string_escape')) ) results['searched'] += 1 return results['searched'] < options.howmany scan_blocks(db_dir, db_env, count_matches) db_env.close() percent = (100.0*results['matched'])/results['checked'] print("Found %d matches in %d blocks (%.1f percent)"%(results['matched'], results['checked'], percent))
def sendbitcoin(address, amount=0, comment="", comment_to=""): txid = sendtoaddress(address, amount, comment, comment_to) if txid['result']: _raw = getrawtransaction(txid['result']) if _raw['result']: ds = BCDataStream() ds.write(binascii.unhexlify(_raw['result'])) _raw['result'] = deserialize.deserialize_TransactionRaw(deserialize.parse_Transaction(ds)) return _raw else: if txid['error']['code']==-4: txid['error']['message']="Insufficient funds" return txid
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 main(): import optparse parser = optparse.OptionParser(usage="%prog [options]") parser.add_option("--datadir", dest="datadir", default=None, help="Look for files here (defaults to bitcoin default)") (options, args) = parser.parse_args() if options.datadir is None: db_dir = determine_db_dir() else: db_dir = options.datadir try: db_env = create_env(db_dir) except DBNoSuchFileError: logging.error("Couldn't open " + db_dir) sys.exit(1) blockfile = open(os.path.join(db_dir, "blk%04d.dat"%(1,)), "rb") block_datastream = BCDataStream() block_datastream.map_file(blockfile, 0) n_transactions = { } v_transactions = { } def gather_stats(block_data): block_datastream.seek_file(block_data['nBlockPos']) data = parse_Block(block_datastream) block_date = date.fromtimestamp(data['nTime']) key = "%d-%02d"%(block_date.year, block_date.month) for txn in data['transactions'][1:]: for txout in txn['txOut']: if key in n_transactions: n_transactions[key] += 1 v_transactions[key] += txout['value'] else: n_transactions[key] = 1 v_transactions[key] = txout['value'] return True scan_blocks(db_dir, db_env, gather_stats) db_env.close() keys = n_transactions.keys() keys.sort() for k in keys: v = v_transactions[k]/1.0e8 print "%s,%d,%.2f"%(k, n_transactions[k], v)
def main(): import optparse parser = optparse.OptionParser(usage="%prog [options]") parser.add_option( "--datadir", dest="datadir", default=None, help="Look for files here (defaults to bitcoin default)" ) (options, args) = parser.parse_args() if options.datadir is None: db_dir = determine_db_dir() else: db_dir = options.datadir try: db_env = create_env(db_dir) except DBNoSuchFileError: logging.error("Couldn't open " + db_dir) sys.exit(1) blockfile = open(os.path.join(db_dir, "blk%04d.dat" % (1,)), "rb") block_datastream = BCDataStream() block_datastream.map_file(blockfile, 0) def gather(block_data): block_datastream.seek_file(block_data["nBlockPos"]) data = parse_Block(block_datastream) height = block_data["nHeight"] coinbase = data["transactions"][0] scriptSig = coinbase["txIn"][0]["scriptSig"] if len(scriptSig) < 4: return True (n,) = struct.unpack_from("<I", scriptSig[0:4]) if n < 6 * 24 * 365.25 * 100: # 200 years of blocks: print("%d: %d (%s)" % (height, n, approx_date(n))) if ord(scriptSig[0]) == 0x03: (n,) = struct.unpack_from("<I", scriptSig[1:4] + "\0") if n < 6 * 24 * 365.25 * 100: # 200 years of blocks: print("%d: PUSH %d (%s)" % (height, n, approx_date(n))) return True scan_blocks(db_dir, db_env, gather) db_env.close()
def get_tx(self,txhash,skip=0): # validation txhash here txhash = txhash.lower() if not re.match(r'^[a-f0-9]{64}$',txhash): return {"error" : "invalid transaction hash format"} try: print "trying ppcoind" tx = self.conn.gettransaction(txhash) confirmations = tx.confirmations; tx = tx.transaction[0] del tx['coindays'] tx['confirmations'] = confirmations for out in tx["outpoints"]: out["value"] = format(int(out["value"]) / 1e6,'.6f') for inp in tx["inpoints"]: inp["value"] = format(int(inp["value"]) / 1e6,'.6f') tx['time'] = datetime.datetime.utcfromtimestamp(tx["time"]).strftime("%Y-%m-%d %H:%M:%S+0000") return tx except bitcoinrpc.exceptions.InvalidAddressOrKey: print "checking elsewhere"; template = self.conn.proxy.getblocktemplate() txns = template["transactions"]; txdata = None for tx in txns: if tx["hash"] == txhash: txdata = tx["data"] break if txdata: raw = BCDataStream() raw.write(txdata.decode('hex_codec')) tx = parse_Transaction(raw) dtx = deserialize_Transaction_json(tx) dtx["confirmations"] = 0 dtx["txid"] = txhash; dtx['time'] = datetime.datetime.utcfromtimestamp(tx["time"]).strftime("%Y-%m-%d %H:%M:%S+0000") #print dtx for inp in dtx["inpoints"]: old_tx = self.get_tx(inp["previoustx"]) #print old_tx inp['value'] = old_tx['outpoints'][inp["previoustxindex"]]['value'] inp['scriptpubkey'] = old_tx['outpoints'][inp["previoustxindex"]]['scriptpubkey'] inp['peercoinaddress'] = old_tx['outpoints'][inp["previoustxindex"]]['peercoinaddress'] return dtx; cherrypy.response.status = 500 return {'error' : 'tx not found'}
def _read_block(db, blkhash): key_prefix = "b"+(blkhash.decode('hex_codec')[::-1]) cursor = db.iterator(prefix=key_prefix) (key, value) = cursor.next() vds = BCDataStream() vds.clear(); vds.write(value) block_data = _parse_block_index(vds) print block_data if block_data['nStatus'] & 8 == False: raise 'no block data, maybe data is downloaded?' return block = _dump_block(datadir, block_data['nFile'], block_data['nBlockPos'], blkhash) block['hash256'] = blkhash block['nHeight'] = block_data['nHeight'] return block
class CachedBlockFile(object): def __init__(self, db_dir): self.datastream = None self.file = None self.n = None self.db_dir = db_dir def get_stream(self, n): if self.n == n: return self.datastream if self.datastream is not None: self.datastream.close_file() self.file.close() self.n = n self.file = open(os.path.join(self.db_dir, "blk%04d.dat"%(n,)), "rb") self.datastream = BCDataStream() self.datastream.map_file(self.file, 0) return self.datastream
def get_stream(self, n): if self.n == n: return self.datastream if self.datastream is not None: self.datastream.close_file() self.file.close() self.n = n self.file = open(os.path.join(self.db_dir, "blk%04d.dat"%(n,)), "rb") self.datastream = BCDataStream() self.datastream.map_file(self.file, 0) return self.datastream
def dump_block_n(datadir, db_env, block_number): """ 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) while block_data["nHeight"] > block_number: block_data = read_block(cursor, block_data["hashPrev"]) print "Block height: " + str(block_data["nHeight"]) _dump_block(datadir, block_data["nFile"], block_data["nBlockPos"], block_data["hash256"], block_data["hashNext"])
def _dump_block(datadir, nFile, nBlockPos, hash256, hashNext, do_print=True, print_raw_tx=False, print_json=False): 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, print_raw_tx) ds.close_file() blockfile.close() if do_print: print "BLOCK "+long_hex(hash256[::-1]) print "Next block: "+long_hex(hashNext[::-1]) print block_string elif print_json: import json print json.dumps({ 'version': d['version'], 'previousblockhash': d['hashPrev'][::-1].encode('hex'), 'transactions' : [ tx_hex['__data__'].encode('hex') for tx_hex in d['transactions'] ], 'time' : d['nTime'], 'bits' : hex(d['nBits']).lstrip("0x"), 'nonce' : d['nNonce'] }) return block_string
def serialize_transaction(chain, tx): ds = BCDataStream.BCDataStream() chain.ds_serialize_transaction(ds, tx) return ds.input
def dump_transaction(datadir, db_env, tx_id): """ Dump a transaction, given hexadecimal tx_id-- either the full ID OR a short_hex version of the id. """ 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) kds = BCDataStream() vds = BCDataStream() n_tx = 0 n_blockindex = 0 key_prefix = "\x02tx"+(tx_id[-4:].decode('hex_codec')[::-1]) 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]) version = vds.read_uint32() tx_pos = _read_CDiskTxPos(vds) if (hash_hex.startswith(tx_id) or short_hex(hash256[::-1]).startswith(tx_id)): _dump_tx(datadir, hash256, tx_pos) (key, value) = cursor.next() db.close()
def update_wallet(db, type, data): """Write a single item to the wallet. db must be open with writable=True. type and data are the type code and data dictionary as parse_wallet would give to item_callback. data's __key__, __value__ and __type__ are ignored; only the primary data fields are used. """ d = data kds = BCDataStream() vds = BCDataStream() # Write the type code to the key kds.write_string(type) vds.write("") # Ensure there is something try: if type == "tx": raise NotImplementedError("Writing items of type 'tx'") kds.write(d['tx_id']) #d.update(parse_WalletTx(vds)) elif type == "name": kds.write(d['hash']) vds.write(d['name']) elif type == "version": vds.write_uint32(d['version']) elif type == "setting": raise NotImplementedError("Writing items of type 'setting'") kds.write_string(d['setting']) #d['value'] = parse_setting(d['setting'], vds) elif type == "key": kds.write_string(d['public_key']) vds.write_string(d['private_key']) elif type == "wkey": kds.write_string(d['public_key']) vds.write_string(d['private_key']) vds.write_int64(d['created']) vds.write_int64(d['expires']) vds.write_string(d['comment']) elif type == "ckey": kds.write_string(d['public_key']) kds.write_string(d['crypted_key']) elif type == "mkey": kds.write_int32(d['nID']) vds.write_string(d['crypted_key']) vds.write_string(d['salt']) vds.write_int32(d['nDeriveIterations']) vds.write_int32(d['nDerivationMethod']) vds.write_string(d['vchOtherDerivationParameters']) elif type == "defaultkey": vds.write_string(d['key']) elif type == "pool": kds.write_int64(d['n']) vds.write_int32(d['nVersion']) vds.write_int64(d['nTime']) vds.write_string(d['public_key']) elif type == "acc": kds.write_string(d['account']) vds.write_int32(d['nVersion']) vds.write_string(d['public_key']) elif type == "acentry": kds.write_string(d['account']) kds.write_uint64(d['n']) vds.write_int32(d['nVersion']) vds.write_int64(d['nCreditDebit']) vds.write_int64(d['nTime']) vds.write_string(d['otherAccount']) vds.write_string(d['comment']) elif type == "bestblock": vds.write_int32(d['nVersion']) vds.write_compact_size(len(d['hashes'])) for h in d['hashes']: vds.write(h) else: print "Unknown key type: "+type # Write the key/value pair to the database db.put(kds.input, vds.input) except Exception, e: print("ERROR writing to wallet.dat, type %s"%type) print("data dictionary: %r"%data)
def dump_accounts(db_env): db = open_wallet(db_env) kds = BCDataStream() vds = BCDataStream() accounts = set() for (key, value) in db.items(): kds.clear(); kds.write(key) vds.clear(); vds.write(value) type = kds.read_string() if type == "acc": accounts.add(kds.read_string()) elif type == "name": accounts.add(vds.read_string()) elif type == "acentry": accounts.add(kds.read_string()) # Note: don't need to add otheraccount, because moves are # always double-entry for name in sorted(accounts): print(name) db.close()
def parse_wallet(db, item_callback): kds = BCDataStream() vds = BCDataStream() for (key, value) in db.items(): d = { } kds.clear(); kds.write(key) vds.clear(); vds.write(value) try: type = kds.read_string() d["__key__"] = key d["__value__"] = value d["__type__"] = type except Exception, e: print("ERROR attempting to read data from wallet.dat, type %s"%type) continue try: if type == "tx": d["tx_id"] = kds.read_bytes(32) d.update(parse_WalletTx(vds)) elif type == "name": d['hash'] = kds.read_string() d['name'] = vds.read_string() elif type == "version": d['version'] = vds.read_uint32() elif type == "setting": d['setting'] = kds.read_string() d['value'] = parse_setting(d['setting'], vds) elif type == "key": d['public_key'] = kds.read_bytes(kds.read_compact_size()) d['private_key'] = vds.read_bytes(vds.read_compact_size()) elif type == "wkey": d['public_key'] = kds.read_bytes(kds.read_compact_size()) d['private_key'] = vds.read_bytes(vds.read_compact_size()) d['created'] = vds.read_int64() d['expires'] = vds.read_int64() d['comment'] = vds.read_string() elif type == "ckey": d['public_key'] = kds.read_bytes(kds.read_compact_size()) d['crypted_key'] = vds.read_bytes(vds.read_compact_size()) elif type == "mkey": d['nID'] = kds.read_int32() d['crypted_key'] = vds.read_bytes(vds.read_compact_size()) d['salt'] = vds.read_bytes(vds.read_compact_size()) d['nDerivationMethod'] = vds.read_int32() d['nDeriveIterations'] = vds.read_int32() d['vchOtherDerivationParameters'] = vds.read_bytes(vds.read_compact_size()) elif type == "defaultkey": d['key'] = vds.read_bytes(vds.read_compact_size()) elif type == "pool": d['n'] = kds.read_int64() d['nVersion'] = vds.read_int32() d['nTime'] = vds.read_int64() d['public_key'] = vds.read_bytes(vds.read_compact_size()) elif type == "acc": d['account'] = kds.read_string() d['nVersion'] = vds.read_int32() d['public_key'] = vds.read_bytes(vds.read_compact_size()) elif type == "acentry": d['account'] = kds.read_string() d['n'] = kds.read_uint64() d['nVersion'] = vds.read_int32() d['nCreditDebit'] = vds.read_int64() d['nTime'] = vds.read_int64() d['otherAccount'] = vds.read_string() d['comment'] = vds.read_string() elif type == "bestblock": d['nVersion'] = vds.read_int32() d.update(parse_BlockLocator(vds)) elif type == "cscript": d['scriptHash'] = kds.read_bytes(20) d['script'] = vds.read_bytes(vds.read_compact_size()) else: print "Skipping item of type "+type continue item_callback(type, d) except Exception, e: print("ERROR parsing wallet.dat, type %s"%type) print("key data in hex: %s"%key.encode('hex_codec')) print("value data in hex: %s"%value.encode('hex_codec'))
def main(): import optparse parser = optparse.OptionParser(usage="%prog [options]") parser.add_option("--datadir", dest="datadir", default=None, help="Look for files here (defaults to bitcoin default)") parser.add_option("--week", dest="week", default=False, action="store_true", help="Dump day-by-day for the last week's worth of blocks") (options, args) = parser.parse_args() if options.datadir is None: db_dir = determine_db_dir() else: db_dir = options.datadir try: db_env = create_env(db_dir) except DBNoSuchFileError: logging.error("Couldn't open " + db_dir) sys.exit(1) blockfile = open(os.path.join(db_dir, "blk%04d.dat"%(1,)), "rb") block_datastream = BCDataStream() block_datastream.map_file(blockfile, 0) n_transactions = defaultdict(int) v_transactions = defaultdict(float) v_transactions_min = defaultdict(float) v_transactions_max = defaultdict(float) def gather_stats(block_data): block_datastream.seek_file(block_data['nBlockPos']) data = parse_Block(block_datastream) block_date = date.fromtimestamp(data['nTime']) key = "%d-%02d"%(block_date.year, block_date.month) for txn in data['transactions'][1:]: values = [] for txout in txn['txOut']: n_transactions[key] += 1 v_transactions[key] += txout['value'] values.append(txout['value']) v_transactions_min[key] += min(values) v_transactions_max[key] += max(values) return True def gather_stats_week(block_data, lastDate): block_datastream.seek_file(block_data['nBlockPos']) data = parse_Block(block_datastream) block_date = date.fromtimestamp(data['nTime']) if block_date < lastDate: return False key = "%d-%02d-%02d"%(block_date.year, block_date.month, block_date.day) for txn in data['transactions'][1:]: values = [] for txout in txn['txOut']: n_transactions[key] += 1 v_transactions[key] += txout['value'] values.append(txout['value']) v_transactions_min[key] += min(values) v_transactions_max[key] += max(values) return True if options.week: lastDate = date.fromordinal(date.today().toordinal()-7) scan_blocks(db_dir, db_env, lambda x: gather_stats_week(x, lastDate) ) else: scan_blocks(db_dir, db_env, gather_stats) db_env.close() print "date,nTransactions,minBTC,maxBTC,totalBTC" keys = n_transactions.keys() keys.sort() for k in keys: v = v_transactions[k]/1.0e8 v_min = v_transactions_min[k]/1.0e8 v_max = v_transactions_max[k]/1.0e8 # Columns are: # month n_transactions min max total # ... where min and max add up just the smallest or largest # output in each transaction; the true value of bitcoins # transferred will be somewhere between min and max. # We don't know how many are transfers-to-self, though, and # this will undercount multi-txout-transactions (which is good # right now, because they're mostly used for mining pool # payouts that arguably shouldn't count). print "%s,%d,%.2f,%.2f,%.2f"%(k, n_transactions[k], v_min, v_max, v)
def serialize_block_header(chain, block): ds = BCDataStream.BCDataStream() chain.ds_serialize_block_header(ds, block) return ds.input
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 dump_addresses(db_env): db = DB(db_env) try: r = db.open("addr.dat", "main", DB_BTREE, DB_THREAD|DB_RDONLY) except DBError: r = True if r is not None: logging.error("Couldn't open addr.dat/main. Try quitting Bitcoin and running this again.") sys.exit(1) kds = BCDataStream() vds = BCDataStream() for (key, value) in db.items(): kds.clear(); kds.write(key) vds.clear(); vds.write(value) type = kds.read_string() if type == "addr": d = parse_CAddress(vds) print(deserialize_CAddress(d)) db.close()
def dump_blkindex_summary(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) kds = BCDataStream() vds = BCDataStream() n_tx = 0 n_blockindex = 0 print("blkindex file summary:") for (key, value) in db.items(): kds.clear(); kds.write(key) vds.clear(); vds.write(value) type = kds.read_string() if type == "tx": n_tx += 1 elif type == "blockindex": n_blockindex += 1 elif type == "version": version = vds.read_int32() print(" Version: %d"%(version,)) elif type == "hashBestChain": hash = vds.read_bytes(32) print(" HashBestChain: %s"%(hash.encode('hex_codec'),)) else: logging.warn("blkindex: unknown type '%s'"%(type,)) continue print(" %d transactions, %d blocks."%(n_tx, n_blockindex)) db.close()
def dump_block(datadir, db_env, block_hash, print_raw_tx=False, print_json=False): """ 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)): if print_json == False: print "Block height: "+str(block_data['nHeight']) _dump_block(datadir, block_data['nFile'], block_data['nBlockPos'], hash256, block_data['hashNext'], print_raw_tx=print_raw_tx) else: _dump_block(datadir, block_data['nFile'], block_data['nBlockPos'], hash256, block_data['hashNext'], print_json=print_json, do_print=False) (key, value) = cursor.next() db.close()
def str_to_ds(s): import BCDataStream ds = BCDataStream.BCDataStream() ds.write(s) return ds
def _read_tx(db, txhash): kds = BCDataStream() vds = BCDataStream() key_prefix = "t"+txhash cursor = db.iterator(prefix=key_prefix) (key, value) = cursor.next() kds.clear(); kds.write(key) vds.clear(); vds.write(value) kds.read_bytes(1) hash256 = (kds.read_bytes(32)) tx_pos = _read_CDiskTxPos(vds) return _dump_tx(datadir, hash256, tx_pos)
def parse_wallet(db, item_callback): kds = BCDataStream() vds = BCDataStream() for (key, value) in db.items(): d = { } kds.clear(); kds.write(key) vds.clear(); vds.write(value) type = kds.read_string() d["__key__"] = key d["__value__"] = value d["__type__"] = type try: if type == "tx": d["tx_id"] = kds.read_bytes(32) d.update(parse_WalletTx(vds)) elif type == "name": d['hash'] = kds.read_string() d['name'] = vds.read_string() elif type == "version": d['version'] = vds.read_uint32() elif type == "setting": d['setting'] = kds.read_string() d['value'] = parse_setting(d['setting'], vds) elif type == "key": d['public_key'] = kds.read_bytes(kds.read_compact_size()) d['private_key'] = vds.read_bytes(vds.read_compact_size()) elif type == "wkey": d['public_key'] = kds.read_bytes(kds.read_compact_size()) d['private_key'] = vds.read_bytes(vds.read_compact_size()) d['created'] = vds.read_int64() d['expires'] = vds.read_int64() d['comment'] = vds.read_string() elif type == "defaultkey": d['key'] = vds.read_bytes(vds.read_compact_size()) elif type == "pool": d['n'] = kds.read_int64() d['nVersion'] = vds.read_int32() d['nTime'] = vds.read_int64() d['public_key'] = vds.read_bytes(vds.read_compact_size()) elif type == "acc": d['account'] = kds.read_string() d['nVersion'] = vds.read_int32() d['public_key'] = vds.read_bytes(vds.read_compact_size()) elif type == "acentry": d['account'] = kds.read_string() d['n'] = kds.read_uint64() d['nVersion'] = vds.read_int32() d['nCreditDebit'] = vds.read_int64() d['nTime'] = vds.read_int64() d['otherAccount'] = vds.read_string() d['comment'] = vds.read_string() else: print "Unknown key type: "+type item_callback(type, d) except Exception, e: print("ERROR parsing wallet.dat, type %s"%type) print("key data in hex: %s"%key.encode('hex_codec')) print("value data in hex: %s"%value.encode('hex_codec'))