2 # Code for parsing the wallet.dat file
11 from BCDataStream import *
12 from base58 import public_key_to_bc_address, bc_address_to_hash_160, hash_160
13 from util import short_hex, long_hex
14 from deserialize import *
16 def open_wallet(db_env, writable=False):
18 flags = DB_THREAD | (DB_CREATE if writable else DB_RDONLY)
20 r = db.open("wallet.dat", "main", DB_BTREE, flags)
25 logging.error("Couldn't open wallet.dat/main. Try quitting Bitcoin and running this again.")
30 def parse_wallet(db, item_callback):
34 for (key, value) in db.items():
37 kds.clear(); kds.write(key)
38 vds.clear(); vds.write(value)
40 type = kds.read_string()
43 d["__value__"] = value
48 d["tx_id"] = kds.read_bytes(32)
49 d.update(parse_WalletTx(vds))
51 d['hash'] = kds.read_string()
52 d['name'] = vds.read_string()
53 elif type == "version":
54 d['version'] = vds.read_uint32()
55 elif type == "setting":
56 d['setting'] = kds.read_string()
57 d['value'] = parse_setting(d['setting'], vds)
59 d['public_key'] = kds.read_bytes(kds.read_compact_size())
60 d['private_key'] = vds.read_bytes(vds.read_compact_size())
62 d['public_key'] = kds.read_bytes(kds.read_compact_size())
63 d['private_key'] = vds.read_bytes(vds.read_compact_size())
64 d['created'] = vds.read_int64()
65 d['expires'] = vds.read_int64()
66 d['comment'] = vds.read_string()
68 d['public_key'] = kds.read_bytes(kds.read_compact_size())
69 d['crypted_key'] = vds.read_bytes(vds.read_compact_size())
71 d['nID'] = kds.read_int32()
72 d['crypted_key'] = vds.read_bytes(vds.read_compact_size())
73 d['salt'] = vds.read_bytes(vds.read_compact_size())
74 d['nDerivationMethod'] = vds.read_int32()
75 d['nDeriveIterations'] = vds.read_int32()
76 d['vchOtherDerivationParameters'] = vds.read_bytes(vds.read_compact_size())
77 elif type == "defaultkey":
78 d['key'] = vds.read_bytes(vds.read_compact_size())
80 d['n'] = kds.read_int64()
81 d['nVersion'] = vds.read_int32()
82 d['nTime'] = vds.read_int64()
83 d['public_key'] = vds.read_bytes(vds.read_compact_size())
85 d['account'] = kds.read_string()
86 d['nVersion'] = vds.read_int32()
87 d['public_key'] = vds.read_bytes(vds.read_compact_size())
88 elif type == "acentry":
89 d['account'] = kds.read_string()
90 d['n'] = kds.read_uint64()
91 d['nVersion'] = vds.read_int32()
92 d['nCreditDebit'] = vds.read_int64()
93 d['nTime'] = vds.read_int64()
94 d['otherAccount'] = vds.read_string()
95 d['comment'] = vds.read_string()
96 elif type == "bestblock":
97 d['nVersion'] = vds.read_int32()
98 d.update(parse_BlockLocator(vds))
100 print "Unknown key type: "+type
102 item_callback(type, d)
105 print("ERROR parsing wallet.dat, type %s"%type)
106 print("key data in hex: %s"%key.encode('hex_codec'))
107 print("value data in hex: %s"%value.encode('hex_codec'))
109 def update_wallet(db, type, data):
110 """Write a single item to the wallet.
111 db must be open with writable=True.
112 type and data are the type code and data dictionary as parse_wallet would
113 give to item_callback.
114 data's __key__, __value__ and __type__ are ignored; only the primary data
121 # Write the type code to the key
122 kds.write_string(type)
123 vds.write("") # Ensure there is something
127 raise NotImplementedError("Writing items of type 'tx'")
128 kds.write(d['tx_id'])
129 #d.update(parse_WalletTx(vds))
133 elif type == "version":
134 vds.write_uint32(d['version'])
135 elif type == "setting":
136 raise NotImplementedError("Writing items of type 'setting'")
137 kds.write_string(d['setting'])
138 #d['value'] = parse_setting(d['setting'], vds)
140 kds.write_string(d['public_key'])
141 vds.write_string(d['private_key'])
143 kds.write_string(d['public_key'])
144 vds.write_string(d['private_key'])
145 vds.write_int64(d['created'])
146 vds.write_int64(d['expires'])
147 vds.write_string(d['comment'])
149 kds.write_string(d['public_key'])
150 kds.write_string(d['crypted_key'])
152 kds.write_int32(d['nID'])
153 vds.write_string(d['crypted_key'])
154 vds.write_string(d['salt'])
155 vds.write_int32(d['nDeriveIterations'])
156 vds.write_int32(d['nDerivationMethod'])
157 vds.write_string(d['vchOtherDerivationParameters'])
158 elif type == "defaultkey":
159 vds.write_string(d['key'])
161 kds.write_int64(d['n'])
162 vds.write_int32(d['nVersion'])
163 vds.write_int64(d['nTime'])
164 vds.write_string(d['public_key'])
166 kds.write_string(d['account'])
167 vds.write_int32(d['nVersion'])
168 vds.write_string(d['public_key'])
169 elif type == "acentry":
170 kds.write_string(d['account'])
171 kds.write_uint64(d['n'])
172 vds.write_int32(d['nVersion'])
173 vds.write_int64(d['nCreditDebit'])
174 vds.write_int64(d['nTime'])
175 vds.write_string(d['otherAccount'])
176 vds.write_string(d['comment'])
177 elif type == "bestblock":
178 vds.write_int32(d['nVersion'])
179 vds.write_compact_size(len(d['hashes']))
180 for h in d['hashes']:
183 print "Unknown key type: "+type
185 # Write the key/value pair to the database
186 db.put(kds.input, vds.input)
189 print("ERROR writing to wallet.dat, type %s"%type)
190 print("data dictionary: %r"%data)
192 def dump_wallet(db_env, print_wallet, print_wallet_transactions, transaction_filter):
193 db = open_wallet(db_env)
195 wallet_transactions = []
196 transaction_index = { }
199 def item_callback(type, d):
201 wallet_transactions.append( d )
202 transaction_index[d['tx_id']] = d
204 owner_keys[public_key_to_bc_address(d['public_key'])] = d['private_key']
206 owner_keys[public_key_to_bc_address(d['public_key'])] = d['crypted_key']
213 print("ADDRESS "+d['hash']+" : "+d['name'])
214 elif type == "version":
215 print("Version: %d"%(d['version'],))
216 elif type == "setting":
217 print(d['setting']+": "+str(d['value']))
219 print("PubKey "+ short_hex(d['public_key']) + " " + public_key_to_bc_address(d['public_key']) +
220 ": PriKey "+ short_hex(d['private_key']))
222 print("WPubKey 0x"+ short_hex(d['public_key']) + " " + public_key_to_bc_address(d['public_key']) +
223 ": WPriKey 0x"+ short_hex(d['crypted_key']))
224 print(" Created: "+time.ctime(d['created'])+" Expires: "+time.ctime(d['expires'])+" Comment: "+d['comment'])
226 print("PubKey "+ short_hex(d['public_key']) + " " + public_key_to_bc_address(d['public_key']) +
227 ": Encrypted PriKey "+ short_hex(d['crypted_key']))
229 print("Master Key %d"%(d['nID']) + ": 0x"+ short_hex(d['crypted_key']) +
230 ", Salt: 0x"+ short_hex(d['salt']) +
231 ". Passphrase hashed %d times with method %d with other parameters 0x"%(d['nDeriveIterations'], d['nDerivationMethod']) +
232 long_hex(d['vchOtherDerivationParameters']))
233 elif type == "defaultkey":
234 print("Default Key: 0x"+ short_hex(d['key']) + " " + public_key_to_bc_address(d['key']))
236 print("Change Pool key %d: %s (Time: %s)"% (d['n'], public_key_to_bc_address(d['public_key']), time.ctime(d['nTime'])))
238 print("Account %s (current key: %s)"%(d['account'], public_key_to_bc_address(d['public_key'])))
239 elif type == "acentry":
240 print("Move '%s' %d (other: '%s', time: %s, entry %d) %s"%
241 (d['account'], d['nCreditDebit'], d['otherAccount'], time.ctime(d['nTime']), d['n'], d['comment']))
242 elif type == "bestblock":
243 print deserialize_BlockLocator(d)
245 print "Unknown key type: "+type
247 parse_wallet(db, item_callback)
249 if print_wallet_transactions:
250 keyfunc = lambda i: i['timeReceived']
251 for d in sorted(wallet_transactions, key=keyfunc):
252 tx_value = deserialize_WalletTx(d, transaction_index, owner_keys)
253 if len(transaction_filter) > 0 and re.search(transaction_filter, tx_value) is None: continue
255 print("==WalletTransaction== "+long_hex(d['tx_id'][::-1]))
260 def dump_accounts(db_env):
261 db = open_wallet(db_env)
268 for (key, value) in db.items():
269 kds.clear(); kds.write(key)
270 vds.clear(); vds.write(value)
272 type = kds.read_string()
275 accounts.add(kds.read_string())
277 accounts.add(vds.read_string())
278 elif type == "acentry":
279 accounts.add(kds.read_string())
280 # Note: don't need to add otheraccount, because moves are
281 # always double-entry
283 for name in sorted(accounts):
288 def rewrite_wallet(db_env, destFileName, pre_put_callback=None):
289 db = open_wallet(db_env)
293 r = db_out.open(destFileName, "main", DB_BTREE, DB_CREATE)
298 logging.error("Couldn't open %s."%destFileName)
301 def item_callback(type, d):
302 if (pre_put_callback is None or pre_put_callback(type, d)):
303 db_out.put(d["__key__"], d["__value__"])
305 parse_wallet(db, item_callback)
310 def trim_wallet(db_env, destFileName, pre_put_callback=None):
311 """Write out ONLY address book public/private keys
312 THIS WILL NOT WRITE OUT 'change' KEYS-- you should
313 send all of your bitcoins to one of your public addresses
316 db = open_wallet(db_env)
319 def gather_pubkeys(type, d):
321 pubkeys.append(bc_address_to_hash_160(d['hash']))
323 parse_wallet(db, gather_pubkeys)
327 r = db_out.open(destFileName, "main", DB_BTREE, DB_CREATE)
332 logging.error("Couldn't open %s."%destFileName)
335 def item_callback(type, d):
337 if type in [ 'version', 'name', 'acc' ]:
339 if type in [ 'key', 'wkey', 'ckey' ] and hash_160(d['public_key']) in pubkeys:
341 if pre_put_callback is not None:
342 should_write = pre_put_callback(type, d, pubkeys)
344 db_out.put(d["__key__"], d["__value__"])
346 parse_wallet(db, item_callback)