Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

361 lines (311 sloc) 11.951 kb
#
# Code for parsing the wallet.dat file
#
from bsddb.db import *
import logging
import re
import sys
import time
from BCDataStream import *
from base58 import public_key_to_bc_address, bc_address_to_hash_160, hash_160
from util import short_hex, long_hex
from deserialize import *
def open_wallet(db_env, writable=False):
db = DB(db_env)
flags = DB_THREAD | (DB_CREATE if writable else DB_RDONLY)
try:
r = db.open("wallet.dat", "main", DB_BTREE, flags)
except DBError:
r = True
if r is not None:
logging.error("Couldn't open wallet.dat/main. Try quitting Bitcoin and running this again.")
sys.exit(1)
return db
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 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_wallet(db_env, print_wallet, print_wallet_transactions, transaction_filter):
db = open_wallet(db_env)
wallet_transactions = []
transaction_index = { }
owner_keys = { }
def item_callback(type, d):
if type == "tx":
wallet_transactions.append( d )
transaction_index[d['tx_id']] = d
elif type == "key":
owner_keys[public_key_to_bc_address(d['public_key'])] = d['private_key']
elif type == "ckey":
owner_keys[public_key_to_bc_address(d['public_key'])] = d['crypted_key']
if not print_wallet:
return
if type == "tx":
return
elif type == "name":
print("ADDRESS "+d['hash']+" : "+d['name'])
elif type == "version":
print("Version: %d"%(d['version'],))
elif type == "setting":
print(d['setting']+": "+str(d['value']))
elif type == "key":
print("PubKey "+ short_hex(d['public_key']) + " " + public_key_to_bc_address(d['public_key']) +
": PriKey "+ short_hex(d['private_key']))
elif type == "wkey":
print("WPubKey 0x"+ short_hex(d['public_key']) + " " + public_key_to_bc_address(d['public_key']) +
": WPriKey 0x"+ short_hex(d['crypted_key']))
print(" Created: "+time.ctime(d['created'])+" Expires: "+time.ctime(d['expires'])+" Comment: "+d['comment'])
elif type == "ckey":
print("PubKey "+ short_hex(d['public_key']) + " " + public_key_to_bc_address(d['public_key']) +
": Encrypted PriKey "+ short_hex(d['crypted_key']))
elif type == "mkey":
print("Master Key %d"%(d['nID']) + ": 0x"+ short_hex(d['crypted_key']) +
", Salt: 0x"+ short_hex(d['salt']) +
". Passphrase hashed %d times with method %d with other parameters 0x"%(d['nDeriveIterations'], d['nDerivationMethod']) +
long_hex(d['vchOtherDerivationParameters']))
elif type == "defaultkey":
print("Default Key: 0x"+ short_hex(d['key']) + " " + public_key_to_bc_address(d['key']))
elif type == "pool":
print("Change Pool key %d: %s (Time: %s)"% (d['n'], public_key_to_bc_address(d['public_key']), time.ctime(d['nTime'])))
elif type == "acc":
print("Account %s (current key: %s)"%(d['account'], public_key_to_bc_address(d['public_key'])))
elif type == "acentry":
print("Move '%s' %d (other: '%s', time: %s, entry %d) %s"%
(d['account'], d['nCreditDebit'], d['otherAccount'], time.ctime(d['nTime']), d['n'], d['comment']))
elif type == "bestblock":
print deserialize_BlockLocator(d)
elif type == "cscript":
print("CScript: %s : %s"%(public_key_to_bc_address(d['scriptHash'], "\x01"), long_hex(d['script'])))
else:
print "Unknown key type: "+type
parse_wallet(db, item_callback)
if print_wallet_transactions:
keyfunc = lambda i: i['timeReceived']
for d in sorted(wallet_transactions, key=keyfunc):
tx_value = deserialize_WalletTx(d, transaction_index, owner_keys)
if len(transaction_filter) > 0 and re.search(transaction_filter, tx_value) is None: continue
print("==WalletTransaction== "+long_hex(d['tx_id'][::-1]))
print(tx_value)
db.close()
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 rewrite_wallet(db_env, destFileName, pre_put_callback=None):
db = open_wallet(db_env)
db_out = DB(db_env)
try:
r = db_out.open(destFileName, "main", DB_BTREE, DB_CREATE)
except DBError:
r = True
if r is not None:
logging.error("Couldn't open %s."%destFileName)
sys.exit(1)
def item_callback(type, d):
if (pre_put_callback is None or pre_put_callback(type, d)):
db_out.put(d["__key__"], d["__value__"])
parse_wallet(db, item_callback)
db_out.close()
db.close()
def trim_wallet(db_env, destFileName, pre_put_callback=None):
"""Write out ONLY address book public/private keys
THIS WILL NOT WRITE OUT 'change' KEYS-- you should
send all of your bitcoins to one of your public addresses
before calling this.
"""
db = open_wallet(db_env)
pubkeys = []
def gather_pubkeys(type, d):
if type == "name":
pubkeys.append(bc_address_to_hash_160(d['hash']))
parse_wallet(db, gather_pubkeys)
db_out = DB(db_env)
try:
r = db_out.open(destFileName, "main", DB_BTREE, DB_CREATE)
except DBError:
r = True
if r is not None:
logging.error("Couldn't open %s."%destFileName)
sys.exit(1)
def item_callback(type, d):
should_write = False
if type in [ 'version', 'name', 'acc' ]:
should_write = True
if type in [ 'key', 'wkey', 'ckey' ] and hash_160(d['public_key']) in pubkeys:
should_write = True
if pre_put_callback is not None:
should_write = pre_put_callback(type, d, pubkeys)
if should_write:
db_out.put(d["__key__"], d["__value__"])
parse_wallet(db, item_callback)
db_out.close()
db.close()
Jump to Line
Something went wrong with that request. Please try again.