diff --git a/pywallet.py b/pywallet.py index 1505524..be46b83 100755 --- a/pywallet.py +++ b/pywallet.py @@ -40,6 +40,9 @@ aversions[0] = 'Bitcoin'; aversions[52] = 'Namecoin'; aversions[111] = 'Testnet'; +def iais(a): + return 's' if a>=2 else '' + def determine_db_dir(): import os import os.path @@ -565,10 +568,37 @@ def open_wallet(db_env, walletfile, writable=False): return db +def inversetxid(txid): + if len(txid) is not 64: + print("Bad txid") + exit(0) + new_txid = "" + for i in range(32): + new_txid += txid[62-2*i]; + new_txid += txid[62-2*i+1]; + return new_txid + def parse_wallet(db, item_callback): kds = BCDataStream() vds = BCDataStream() + + def parse_TxIn(vds): + d = {} + d['prevout_hash'] = vds.read_bytes(32).encode('hex') + d['prevout_n'] = vds.read_uint32() + d['scriptSig'] = vds.read_bytes(vds.read_compact_size()).encode('hex') + d['sequence'] = vds.read_uint32() + return d + + + def parse_TxOut(vds): + d = {} + d['value'] = vds.read_int64()/1e8 + d['scriptPubKey'] = vds.read_bytes(vds.read_compact_size()).encode('hex') + return d + + for (key, value) in db.items(): d = { } @@ -583,7 +613,19 @@ def parse_wallet(db, item_callback): try: if type == "tx": - d["tx_id"] = kds.read_bytes(32) + d["tx_id"] = inversetxid(kds.read_bytes(32).encode('hex_codec')) + start = vds.read_cursor + d['version'] = vds.read_int32() + n_vin = vds.read_compact_size() + d['txIn'] = [] + for i in xrange(n_vin): + d['txIn'].append(parse_TxIn(vds)) + n_vout = vds.read_compact_size() + d['txOut'] = [] + for i in xrange(n_vout): + d['txOut'].append(parse_TxOut(vds)) + d['lockTime'] = vds.read_uint32() + d['tx'] = vds.input[start:vds.read_cursor] elif type == "name": d['hash'] = kds.read_string() d['name'] = vds.read_string() @@ -633,6 +675,42 @@ def parse_wallet(db, item_callback): print("value data in hex: %s"%value.encode('hex_codec')) sys.exit(1) +def delete_from_wallet(db_env, walletfile, typedel, keydel): + db = open_wallet(db_env, walletfile, True) + kds = BCDataStream() + vds = BCDataStream() + + deleted_items = 0 + for (key, value) in db.items(): + kds.clear(); kds.write(key) + vds.clear(); vds.write(value) + type = kds.read_string() + + if typedel == "tx": + if type == "tx": + if keydel == inversetxid(kds.read_bytes(32).encode('hex_codec')): + db.delete(key) + deleted_items+=1 + elif typedel == "key": + if type == "key": + if keydel == public_key_to_bc_address(kds.read_bytes(kds.read_compact_size())): + db.delete(key) + deleted_items+=1 + elif type == "pool": + vds.read_int32() + vds.read_int64() + if keydel == public_key_to_bc_address(vds.read_bytes(vds.read_compact_size())): + db.delete(key) + deleted_items+=1 + elif type == "name": + if keydel == kds.read_string(): + db.delete(key) + deleted_items+=1 + + + db.close() + return deleted_items + def update_wallet(db, type, data): """Write a single item to the wallet. db must be open with writable=True. @@ -732,11 +810,14 @@ def read_wallet(json_db, db_env, walletfile, print_wallet, print_wallet_transact json_db['keys'] = [] json_db['pool'] = [] + json_db['tx'] = [] json_db['names'] = {} def item_callback(type, d): + if type == "tx": + json_db['tx'].append({"txid" : d['tx_id'], "txin" : d['txIn'], "txout" : d['txOut']}) - if type == "name": + elif type == "name": json_db['names'][d['hash']] = d['name'] elif type == "version": @@ -797,8 +878,8 @@ def read_wallet(json_db, db_env, walletfile, print_wallet, print_wallet_transact else: k["reserve"] = 1 - del(json_db['pool']) - del(json_db['names']) +# del(json_db['pool']) +# del(json_db['names']) def importprivkey(db, sec, label, reserve, keyishex): if keyishex is None: @@ -871,7 +952,7 @@ class WIRoot(resource.Resource): Wallet Filename:
\ \ \ - \ + \
' InfoForm = '

Get some info about one key:

\ @@ -900,6 +981,18 @@ class WIRoot(resource.Resource): \

' + DeleteForm = '

Delete a key from your wallet:

\ + Wallet Directory:
\ + Wallet Filename:
\ + Key:
\ + Type:
\ + Transaction
\ + Bitcoin address
\ + \ + \ + \ +

' + BalanceForm = '

Print the balance of a Bitcoin address:

\ Key:
\

\ @@ -909,6 +1002,15 @@ class WIRoot(resource.Resource): Misc = '' Javascript = '' - page = 'Pywallet Web Interface' + header + Javascript + DWForm + InfoForm + ImportForm + BalanceForm + Misc + '' + page = 'Pywallet Web Interface' + header + Javascript + DWForm + InfoForm + ImportForm + DeleteForm + BalanceForm + Misc + '' return page def getChild(self, name, request): @@ -1060,6 +1188,30 @@ class WIBalance(resource.Resource): def render_POST(self, request): return self.render_GET(request) +class WIDelete(resource.Resource): + + def render_GET(self, request): + try: + wdir=request.args['dir'][0] + wname=request.args['name'][0] + keydel=request.args['keydel'][0] + typedel=request.args['typedel'][0] + db_env = create_env(wdir) + + if not os.path.isfile(wdir+"/"+wname): + return '%s/%s doesn\'t exist'%(wdir, wname) + + deleted_items = delete_from_wallet(db_env, wname, typedel, keydel) + + return "%s:%s has been successfully deleted from %s/%s, resulting in %d deleted item%s"%(typedel, keydel, wdir, wname, deleted_items, iais(deleted_items)) + + except: + log.err() + return 'Error in delete page' + + def render_POST(self, request): + return self.render_GET(request) + class WIInfo(resource.Resource): def render_GET(self, request): @@ -1215,6 +1367,7 @@ if __name__ == '__main__': 'DumpWallet': WIDumpWallet(), 'Import': WIImport(), 'Info': WIInfo(), + 'Delete': WIDelete(), 'Balance': WIBalance() }