From 3f8641e7c40cb659cd5e275952cf6e5def2aabfa Mon Sep 17 00:00:00 2001 From: jackjack-jj Date: Sun, 14 Apr 2013 22:57:34 +0200 Subject: [PATCH] v2.0: ui, tx creation and few minor changes --- pywallet.py | 1152 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 1119 insertions(+), 33 deletions(-) diff --git a/pywallet.py b/pywallet.py index 3908d1b..1749273 100755 --- a/pywallet.py +++ b/pywallet.py @@ -1,5 +1,6 @@ #!/usr/bin/env python -pywversion="1.9.4" +#-*- coding: utf-8 -*- +pywversion="2.0" never_update=False # @@ -21,8 +22,8 @@ except: missing_dep.append('bsddb') import os, sys, time -pyw_filename = sys.argv[0].split('/')[len(sys.argv[0].split('/'))-1] -pyw_path = os.getcwd() +pyw_filename = os.path.basename(__file__) +pyw_path = os.path.dirname(os.path.realpath(__file__)) try: for i in os.listdir('/usr/lib/python2.5/site-packages'): @@ -1431,8 +1432,11 @@ def md5_2(a): return hashlib.md5(a).digest() def md5_file(nf): + try: fichier = file(nf, 'r').read() return md5_2(fichier) + except: + return 'zz' def md5_onlinefile(add): page = urllib.urlopen(add).read() @@ -2038,8 +2042,9 @@ def rewrite_wallet(db_env, walletfile, destFileName, pre_put_callback=None): # wallet.dat reader / writer +addr_to_keys={} def read_wallet(json_db, db_env, walletfile, print_wallet, print_wallet_transactions, transaction_filter, include_balance, vers=-1, FillPool=False): - global passphrase + global passphrase, addr_to_keys crypted=False private_keys = [] @@ -2085,6 +2090,7 @@ def read_wallet(json_db, db_env, walletfile, print_wallet, print_wallet_transact sec = SecretToASecret(PrivKeyToSecret(d['private_key']), compressed) hexsec = ASecretToSecret(sec).encode('hex') private_keys.append(sec) + addr_to_keys[addr]=[hexsec, d['public_key'].encode('hex')] json_db['keys'].append({'addr' : addr, 'sec' : sec, 'hexsec' : hexsec, 'secret' : hexsec, 'pubkey':d['public_key'].encode('hex'), 'compressed':compressed, 'private':d['private_key'].encode('hex')}) elif type == "wkey": @@ -2134,7 +2140,7 @@ def read_wallet(json_db, db_env, walletfile, print_wallet, print_wallet_transact else: json_db[type] = 'unsupported' - print d + print "Wallet data not recognized: "+str(d) list_of_reserve_not_in_pool=[] parse_wallet(db, item_callback) @@ -2201,8 +2207,10 @@ def read_wallet(json_db, db_env, walletfile, print_wallet, print_wallet_transact sec = SecretToASecret(secret, compressed) k['sec'] = sec + k['hexsec'] = sec k['secret'] = secret.encode('hex') k['compressed'] = compressed + addr_to_keys[k['addr']]=[sec, k['pubkey']] # del(k['ckey']) # del(k['secret']) # del(k['pubkey']) @@ -2326,7 +2334,499 @@ def keyinfo(sec, keyishex): return True +def css_wui(): + return """html, body { + height: 100%; + width: 100%; + padding: 0; + margin: 0; +} + +body { + margin: 0px; + padding: 0px; + background: url(data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAABLAAD/4QMpaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjAtYzA2MSA2NC4xNDA5NDksIDIwMTAvMTIvMDctMTA6NTc6MDEgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzUgV2luZG93cyIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozRjJGNUI0ODZBN0YxMUUyQkZGRUNDQzgwNjYxQkJENCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozRjJGNUI0OTZBN0YxMUUyQkZGRUNDQzgwNjYxQkJENCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjNGMkY1QjQ2NkE3RjExRTJCRkZFQ0NDODA2NjFCQkQ0IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjNGMkY1QjQ3NkE3RjExRTJCRkZFQ0NDODA2NjFCQkQ0Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+/+4ADkFkb2JlAGTAAAAAAf/bAIQAAwICAgICAwICAwUDAwMFBQQDAwQF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%3D%3D) repeat; + font-family: 'Open Sans', sans-serif; + font-size: 10pt; + color: #B0B0B0; +} + + +h1, h2, h3 { + margin: 0; + padding: 0; +} + +h2 +{ + font-weight: 400; + font-family: 'Archivo Narrow', sans-serif; + font-size: 2.50em; +} + +p, ol, ul { + margin-top: 0px; +} + +p { + line-height: 180%; +} + +strong { +} + +a { + color: #1492C4; +} + +a:hover { + text-decoration: none; +} + +a img { + border: none; +} + +img.border { + border: 10px solid rgba(255,255,255,.10); +} + +img.alignleft { + float: left; + margin-right: 30px; +} + +img.alignright { + float: right; +} + +img.aligncenter { + margin: 0px auto; +} + +hr { + display: none; +} + +#retour-pyw{ + overflow: auto; +} + +#uptodate{ + position:absolute; + top:0px; + right:0px; + background: rgba(0,0,0,0.70); + padding:10px; +} + +#full-screen-background-image { + z-index: -999; + min-height: 100%; + min-width: 1024px; + width: 100%; + height: auto; + position: fixed; + top: 0; + left: 0; +} + +#wrapper { + position: relative; + width: 100%; + min-height: 400px; + #margin: 30px auto; + margin-top:10px; #decalage p/r haut +} + +#wrapper { + overflow: hidden; +} + +.container { + width: 1000px; + margin: 0px auto; +} + +.clearfix { + clear: both; +} + +/** HEADER */ + +#header-wrapper-title +{ + overflow: hidden; + height: 80px; + margin-bottom: 10px; + background: rgba(0,0,0,0); +} + +#header-wrapper +{ + overflow: hidden; + height: 50px; + margin-bottom: 20px; + background: rgba(0,0,0,0.70); +} + +#header { + overflow: hidden; +} + +/** LOGO */ + +#logo { + float: left; + #width: 300px; + height: 50px; + +} + +#logo h1, #logo p { + margin: 0px; + line-height: normal; +} + +#logo h1 a { + padding-left: 00px; + text-decoration: none; + font-size: 2.50em; + font-weight: 400; + font-family: 'Archivo Narrow', sans-serif; + color: #FFFFFF; +} + +/** MENU */ + +#menu { + float: left; + height: 50px; +} + +#menu ul { + margin: 0px; + padding: 0px; + list-style: none; + line-height: normal; +} + +#menu li { + float: left; + margin-right: 10px; + padding: 0px 5px 0px 5px; +} + +#menu a { + display: block; + height: 50px; + padding: 0px 10px; + line-height: 50px; + text-decoration: none; + text-transform: uppercase; + color: #FFFFFF; +} + +#menu a:hover { + text-decoration: none; + background: rgba(0,0,0,0.70); +} + +#menu .active +{ + background: rgba(0,0,0,0.70); +} + +/** PAGE */ + +#page { + overflow: hidden; + margin-bottom: 20px; +} + +/** CONTENT */ + +#content { + float: left; + width: 950px; + padding: 40px; + background: rgba(0,0,0,0.70); +} + +#content h2 a +{ + display: block; + padding: 0px 0px 20px 0px; + text-decoration: none; + color: #FFFFFF; +} + +#content #box1 +{ + margin-bottom: 0px; +} + +/** SIDEBAR */ + +#sidebar { + float: right; + width: 350px; + padding: 20px; + background: rgba(0,0,0,0.70); +} + +#sidebar h2 +{ + padding: 0px 0px 00px 0px; + color: #FFFFFF; +} + +/* Footer */ + +#footer { + overflow: hidden; + margin: 00px auto 0px auto; + padding: 10px 0px; + background: rgba(0,0,0,0.70); +} + +#footer p { + text-align: center; + font-size: 12px; +} + +#footer a { +} + +/** LIST STYLE 1 */ + +ul.style1 { + margin: 0px; + padding: 10px 0px 0px 0px; + list-style: none; +} + +ul.style1 li { + clear: both; + margin-bottom: 25px; + padding: 30px 0px 40px 0px; + border-top: 1px solid #000000; + box-shadow: inset 0 1px 0 rgba(255,255,255,.10); +} + +ul.style1 h3 { + padding-bottom: 5px; + font-size: 14px; + color: #FFFFFF; +} + +ul.style1 p { + line-height: 150%; +} + +ul.style1 .button-style { + float: left; + margin-top: 0px; +} + +ul.style1 .first { + padding-top: 0px; + border-top: none; + box-shadow: none; +} + +/** LIST STYLE 3 */ + +ul.style3 { + margin: 0px; + padding: 0px; + list-style: none; +} + +ul.style3 li { + padding: 10px 0px 10px 0px; + border-top: 1px solid #000000; + box-shadow: inset 0 1px 0 rgba(255,255,255,.10); +} + +ul.style3 a { + text-decoration: none; + color: #949494; +} + +ul.style3 a:hover { + text-decoration: underline; +} + +ul.style3 .first { + padding-top: 0px; + border-top: none; + box-shadow: none; +} + +ul.style3 .date { + width: 87px; + background-color: #1F768D; + margin-top: 20px; + height: 24px; + line-height: 24px; + text-align: center; + font-size: 12px; + color: #FFFFFF; +} + +ul.style3 .first .date +{ + margin-top: 0px; +} + +.button-style +{ + display: inline-block; + background-color: #1F768D; + margin-top: 0px; + padding: 5px 30px; + height: 24px; + line-height: 24px; + text-decoration: none; + text-align: center; + color: #FFFFFF; +} + +.button-style-red +{ + color: #ffffff; + display: inline-block; + background-color: #a12323; + margin-top: 20px; + padding: 5px 30px; + height: 24px; + line-height: 24px; + text-decoration: none; + text-align: center; +} + +.entry +{ + margin-bottom: 30px; +} +""" + +def onclick_on_tab(page): + list=['DumpPage','ImportPage','DeletePage','InfoPage','AboutPage','PassphrasePage','TxPage'] + r='' + for p in list: + if p!=page: + r+="document.getElementById('"+p+"').style.display='none';" + r+="document.getElementById('"+p+"Button').className='';" + r+="document.getElementById('"+page+"').style.display='block';" + r+="document.getElementById('"+page+"Button').className='active';" + return r + +def html_wui(listcontent,uptodate_text): + global pywversion + return """ + + + +Pywallet Web Interface - Pywallet """+pywversion+""" + + + + + +
+ +
+
 
+ +
+
+
+ """+listcontent+""" +
+ +
+ +
+
"""+uptodate_text+"""
+ + +""" + def WI_FormInit(title, action, divname): + return "
  • %s

    "%title return '

      '+title+'

    ' def WI_InputText(label, name, id, value, size=30): @@ -2336,8 +2836,8 @@ def WI_InputPassword(label, name, id, value, size=30): return '%s
    '%(label, name, id, value, size) def WI_Submit(value, local_block, local_button, function): - return ''%(value, local_block, local_button, function) - + return """
    %s"""%(function,value) + def WI_CloseButton(local_block, local_button): return ''%(local_block, local_button, local_button) @@ -2345,7 +2845,7 @@ def WI_ReturnDiv(local_block): return ''%(local_block) def WI_FormEnd(): - return '

    ' + return "
  • " def WI_RadioButton(name, value, id, checked, label): return '   %s
    '%(name, value, id, checked, label) @@ -2353,6 +2853,9 @@ def WI_RadioButton(name, value, id, checked, label): def WI_Checkbox(name, value, id, other, label): return '%s'%(name, value, id, other, label) +def WI_Endiv(t,name,title, desc,hidden=False): + return '

    '+title+'

    '+X_if_else('

    '+desc+'

    ',desc!='','')+'
      '+t+'
    ' + def WI_AjaxFunction(name, command_when_ready, query_string, command_until_ready): return '\n\ function ajax%s(){\n\ @@ -2445,13 +2948,21 @@ def import_csv_keys(filename, wdir, wname, nbremax=9999999): return True +def dep_text_aboutpage(val): + if val: + return "Not found" + else: + return "Found" + +CTX_adds='' + if 'twisted' not in missing_dep: class WIRoot(resource.Resource): def render_GET(self, request): try: request.args['update'][0] - update_pyw() + return update_pyw() except: True @@ -2470,7 +2981,7 @@ if 'twisted' not in missing_dep: X_if_else( 'Pywallet is up-to-date', uptodate, - 'Pywallet is NOT up-to-date
    Click to update, then restart Pywallet'), + 'Pywallet is not up-to-date
    Click to update'), checking_finished, 'Checking version...' ) @@ -2612,10 +3123,33 @@ if 'twisted' not in missing_dep: WI_InputText('Key:', 'key', 'bf-key', '', 35) + \ '
    ' + \ WI_FormEnd() + + global CTX_adds, addr_to_keys + CTX_adds2=CTX_adds.split('|')+addr_to_keys.keys() + + + CreateTxForm = WI_FormInit('Create transaction', 'CTX', 'divformctx') + \ + X_if_else("Additional addresses used: " + ', '.join(CTX_adds.split('|'))+"

    ",len(CTX_adds)>0,"No additional addresses used

    ") + \ + listtx_txt(CTX_adds) + \ + WI_FormEnd() + + CreateTxForm2 = WI_FormInit('Check addresses funds', 'ListTransactions', 'divformctx') + \ + WI_InputText('Addresses: ', 'adds', 'ctx-adds', '', 35) + \ + WI_Submit('Check ', '', '', 'ajaxCTx') + \ + WI_FormEnd() Misc = '' Javascript = '' # WI_AjaxFunction('Import', 'document.getElementById("ImportDiv").innerHTML = ajaxRequest.responseText;', '"/Import?dir="+document.getElementById("impf-dir").value+"&name="+document.getElementById("impf-name").value+"&key="+document.getElementById("impf-key").value+"&label="+document.getElementById("impf-label").value+"&vers="+document.getElementById("impf-vers").value+"&format="+(document.getElementById("impf-hex").checked?"hex":"reg")+(document.getElementById("impf-reserve").checked?"&reserve=1":"")', 'document.getElementById("ImportDiv").innerHTML = "Loading...";') + \ page = 'Pywallet Web Interface' + header + Javascript + CPPForm + DWForm + MWForm + DKForm + IKForm + DTxForm + InfoForm + ImportForm + ImportTxForm + DeleteForm + BalanceForm + Misc + '' + + AboutPage="\ +Pywallet is a tool to manage wallet files, developped by jackjack. Support thread is on bitcointalk.
    \ +
    \ +To support pywallet's development or if you think it's worth something, you can send anything you want to 1AQDfx22pKGgXnUZFL1e4UKos3QqvRzNh5.\ +\ +



    Dependencies:
    \ + \ +    ecdsa: "+dep_text_aboutpage('ecdsa' in missing_dep)+"\ + \ +

    Pywallet path:   "+pyw_path+"/"+pyw_filename+"\ + " + + return html_wui(Javascript + \ + WI_Endiv(DWForm+DKForm+DTxForm, 'DumpPage', 'Dump', '') + \ + WI_Endiv(ImportForm+IKForm+MWForm+ImportTxForm,'ImportPage', 'Import', "Don't forget to close Bitcoin when you modify your wallet", True) + \ + WI_Endiv(DeleteForm,'DeletePage', 'Delete', "Don't forget to close Bitcoin when you modify your wallet", True) + \ + WI_Endiv(CPPForm,'PassphrasePage', 'Change passphrase', '', True) + \ + WI_Endiv(InfoForm+BalanceForm,'InfoPage', 'Info', '', True) + \ + WI_Endiv(CreateTxForm2+CreateTxForm,'TxPage', 'Manage transactions', 'You can here create your own transactions.
    By default, the unspent transactions from addresses previously dumped are shown, but you can add other addresses to check.
    You can\'t create a transaction if you didn\'t dump the private keys of each input beforehand.', True) + \ + WI_Endiv(AboutPage,'AboutPage','About','', True) + ,check_version_text + ) + + return page def getChild(self, name, request): @@ -2875,8 +3436,9 @@ def ct(l_prevh, l_prevn, l_prevsig, l_prevpubkey, l_value_out, l_pubkey_out, is_ txin_ret += inverse_str("%08x"%l_prevn[i]) if scriptSig: - txin_ret2 += "%02x"%(len(l_prevsig[i])/2) + txin_ret2 += "%02x"%(1+len(l_prevsig[i])/2) txin_ret2 += l_prevsig[i] + txin_ret2 += "01" txin_ret2 += "%02x"%(len(l_prevpubkey[i])/2) txin_ret2 += l_prevpubkey[i] @@ -2886,6 +3448,8 @@ def ct(l_prevh, l_prevn, l_prevsig, l_prevpubkey, l_value_out, l_pubkey_out, is_ elif index == i: txin_ret += "%02x"%(len(oldScriptPubkey)/2) txin_ret += oldScriptPubkey + else: + txin_ret += "00" ret += txin_ret ret += "ffffffff" @@ -2910,7 +3474,46 @@ def ct(l_prevh, l_prevn, l_prevsig, l_prevpubkey, l_value_out, l_pubkey_out, is_ if not scriptSig: ret += "01000000" return ret + +def create_transaction(secret_key, hashes_txin, indexes_txin, pubkey_txin, prevScriptPubKey, amounts_txout, scriptPubkey): + li1 = len(secret_key) + li2 = len(hashes_txin) + li3 = len(indexes_txin) + li4 = len(pubkey_txin) + li5 = len(prevScriptPubKey) + + if li1 != li2 or li2 != li3 or li3 != li4 or li4 != li5: + print("Error in the number of tx inputs") + exit(0) + lo1 = len(amounts_txout) + lo2 = len(scriptPubkey) + + if lo1 != lo2: + print("Error in the number of tx outputs") + exit(0) + + sig_txin = [] + i=0 + for cpt in hashes_txin: + sig_txin.append(sign_message(secret_key[i].decode('hex'), ct(hashes_txin, indexes_txin, sig_txin, pubkey_txin, amounts_txout, scriptPubkey, i, prevScriptPubKey[i]), True)+"01") + i+=1 + + tx = ct(hashes_txin, indexes_txin, sig_txin, pubkey_txin, amounts_txout, scriptPubkey) + hashtx = Hash(tx.decode('hex')).encode('hex') + + for i in range(len(sig_txin)): + try: + verify_message_signature(pubkey_txin[i], sig_txin[i][:-2], ct(hashes_txin, indexes_txin, sig_txin, pubkey_txin, amounts_txout, scriptPubkey, i, prevScriptPubKey[i]), True) + print("sig %2d: verif ok"%i) + except: + print("sig %2d: verif error"%i) + exit(0) + +# tx += end_of_wallettx([], int(time.time())) +# return [inverse_str(hashtx), "027478" + hashtx, tx] + return [inverse_str(hashtx), "", tx] + def inverse_str(string): ret = "" for i in range(len(string)/2): @@ -2918,6 +3521,302 @@ def inverse_str(string): ret += string[len(string)-2-2*i+1]; return ret +def read_table(table, beg, end): + rows = table.split(beg) + for i in range(len(rows)): + rows[i] = rows[i].split(end)[0] + return rows + +def read_blockexplorer_table(table): + cell = [] + rows = read_table(table, '', '') + for i in range(len(rows)): + cell.append(read_table(rows[i], '', '')) + del cell[i][0] + del cell[0] + del cell[0] + return cell + +txin_amounts = {} + +def bc_address_to_available_tx(address, testnet=False): + TN="" + if testnet: + TN="testnet" + + blockexplorer_url = "http://blockexplorer.com/"+TN+"/address/" + ret = "" + txin = [] + txin_no = {} + global txin_amounts + txout = [] + balance = 0 + txin_is_used = {} + + page = urllib.urlopen("%s/%s" % (blockexplorer_url, address)) + try: + table = page.read().split('')[1] + table = table.split("
    ")[0] + except: + return {address:[]} + + cell = read_blockexplorer_table(table) + + for i in range(len(cell)): + txhash = read_table(cell[i][0], '/tx/', '#')[1] + post_hash = read_table(cell[i][0], '#', '">')[1] + io = post_hash[0] + no_tx = post_hash[1:] + if io in 'i': + txout.append([txhash, post_hash]) + else: + txin.append(txhash+no_tx) + txin_no[txhash+no_tx] = post_hash[1:] + txin_is_used[txhash+no_tx] = 0 + + #hashblock = read_table(cell[i][1], '/block/', '">')[1] + #blocknumber = read_table(cell[i][1], 'Block ', '')[1] + + txin_amounts[txhash+no_tx] = round(float(cell[i][2]), 8) + +# if cell[i][3][:4] in 'Sent' and io in 'o': +# print(cell[i][3][:4]) +# print(io) +# return 'error' +# if cell[i][3][:4] in 'Rece' and io in 'i': +# print(cell[i][3][:4]) +# print(io) +# return 'error' + + balance = round(float(cell[i][5]), 8) + + + for tx in txout: + pagetx = urllib.urlopen("http://blockexplorer.com/"+TN+"/tx/"+tx[0]) + table_in = pagetx.read().split('Outputs')[0].split('')[1].split("
    ")[0] + + cell = read_blockexplorer_table(table_in) + for i in range(len(cell)): + txhash = read_table(cell[i][0], '/tx/', '#')[1] + no_tx = read_table(cell[i][0], '#', '">')[1][1:] + + if txhash+no_tx in txin: + txin_is_used[txhash+no_tx] = 1 + + ret = [] + for tx in txin: + if not txin_is_used[tx]: + ret.append([tx,txin_amounts[tx],txin_no[tx]]) + + return {address : ret} + +def write_avtx(list_avtx, testnet=False): + TN="" + if testnet: + TN="testnet" + gret = "" + for add in list_avtx: + notnull = False + try: + hexsec = " -> " + bc_address_to_sec[add] + except: + hexsec = "" + ret = '' + a = list_avtx[add] + for array in a: + notnull = True + no_tx = array[0][64:] + array[0] = array[0][:64] + link = "http://blockexplorer.com/"+TN+"/rawtx/"+array[0] + pagetx = urllib.urlopen(link) + ScriptPubkey = str(json.loads(pagetx.read())['out'][int(array[2])]['scriptPubKey']) +# ret += '' + array[0] + "#" + no_tx + ": " + str(array[1]) + " & " + ScriptPubkey + "
    " + ret += '" + ret+="" +# ret += "
    " + "
    " + if notnull is False: + ret = "" + gret += ret + gret=gret[:-len("")] + + return gret+"
    ' + add + "" + hexsec + '
    ' + array[0] + "" + str(array[1]) + "" + ScriptPubkey + "
    " + +ct_txin = [] +ct_txout = [] + + +empty_txin={'hash':'', 'index':'', 'sig':'##', 'pubkey':'', 'oldscript':'', 'addr':''} +empty_txout={'amount':'', 'script':''} + +class tx(): + ins=[] + outs=[] + tosign=False + + def hashtypeone(index,script): + global empty_txin + for i in range(len(ins)): + self.ins[i]=empty_txin + self.ins[index]['pubkey']="" + self.ins[index]['oldscript']=s + self.tosign=True + + def copy(): + r=tx() + r.ins=self.ins[:] + r.outs=self.outs[:] + return r + + def sign(n=-1): + if n==-1: + for i in range(len(ins)): + self.sign(i) + return "done" + + global json_db + txcopy=self.copy() + txcopy.hashtypeone(i, self.ins[n]['oldscript']) + + sec='' + for k in json_db['keys']: + if k['addr']==self.ins[n]['addr'] and 'hexsec' in k: + sec=k['hexsec'] + if sec=='': + print "priv key not found (addr:"+self.ins[n]['addr']+")" + return "" + + self.ins[n]['sig']=sign_message(sec.decode('hex'), txcopy.get_tx(), True) + + def ser(): + r={} + r['ins']=self.ins + r['outs']=self.outs + r['tosign']=self.tosign + return json.dumps(r) + + def unser(r): + s=json.loads(r) + self.ins=s['ins'] + self.outs=s['outs'] + self.tosign=s['tosign'] + + def get_tx(): + r='' + ret += inverse_str("%08x"%1) + ret += "%02x"%len(self.ins) + + for i in range(len(self.ins)): + txin=self.ins[i] + ret += inverse_str(txin['hash']) + ret += inverse_str("%08x"%txin['index']) + + if txin['pubkey']!="": + tmp += "%02x"%(1+len(txin['sig'])/2) + tmp += txin['sig'] + tmp += "01" + tmp += "%02x"%(len(txin['pubkey'])/2) + tmp += txin['pubkey'] + + ret += "%02x"%(len(tmp)/2) + ret += tmp + + elif txin['oldscript']!="": + ret += "%02x"%(len(txin['oldscript'])/2) + ret += txin['oldscript'] + + else: + ret += "00" + + ret += "ffffffff" + + ret += "%02x"%len(self.outs) + + for i in range(len(self.outs)): + txout=self.outs[i] + ret += inverse_str("%016x"%(txout['amount'])) + + if txout['script'][:2]=='s:': #script + script=txout['script'][:2] + ret += "%02x"%(len(script)/2) + ret += script + else: #address + ret += "%02x"%(len(txout['script'])/2+5) + ret += "%02x"%OP_DUP + ret += "%02x"%OP_HASH160 + ret += "%02x"%(len(txout['script'])/2) + ret += txout['script'] + ret += "%02x"%OP_EQUALVERIFY + ret += "%02x"%OP_CHECKSIG + + ret += "00000000" + if not self.tosign: + ret += "01000000" + return ret + + +def listtx_txt(adds): + untx_site="http://blockchain.info/unspent?active=" + ret='' + table="""
    """ + utx=untx_site+adds + try: + utxs=json.loads(urllib.urlopen(utx).read())["unspent_outputs"] + except: + return "No inputs" + + table+="\ + \ + \ + \ + \ + " + for tx in utxs: + txhash=str(tx["tx_hash"]).decode('hex')[::-1].encode('hex') + txn=int(tx["tx_output_n"]) + txscript=str(tx["script"]) + txvalue=int(tx["value"]) + table+="" + table+="" +# table+="" + table+="" + table+="" + if txscript[:6]+txscript[-4:]=="76a91488ac": + table+="" + table+="" + else: + table+="" + + table+="" + table+="\n" + table+="
    UseTx hashScriptAmount
    \ + \ + \ + \ + \ +\ + "+a+""+txhash+"Address "+hash_160_to_bc_address(txscript[6:-4].decode('hex'))+""+txscript+""+str(txvalue/1e8)+"
    " + ret+=table + + ret+="0 BTC (inputs) - 0 BTC (outputs) = 0 BTC (fee)

    " + + txouts="" + nbretxouts=30 + unserouts=["parseFloat(document.getElementById(\"txout_am_"+str(i)+"\").value)" for i in range(nbretxouts)] + serouts="+".join(unserouts) + for i in range(nbretxouts): + txouts+="\ +Amount:     Script: \ +\ +\ +\ +
    "+X_if_else("",i>=2,"")+"
    " + + ret+=txouts + ret+="
    " +# ret+=WI_Submit('Create', '', '', 'ajaxCTX2') + + return ret + if 'twisted' not in missing_dep: class WIInfo(resource.Resource): @@ -3050,6 +3949,171 @@ if 'twisted' not in missing_dep: def render_POST(self, request): return self.render_GET(request) + class WICTListTx(resource.Resource): + def render_GET(self, request): + global CTX_adds + try: + adds=request.args['addresses'][0] + CTX_adds=adds + except: + return "You must provide at least one address to see the transaction you can spend. Divided by |" + + ret="" + ret=listtx_txt(adds) + return "Refresh to display available incoming transactions" + + def render_POST(self, request): + return self.render_GET(request) + + class WICT(resource.Resource): + def render_GET(self, request): + #CT?sec=s&hashesin=h&indexes=1&pubkeys=p&prevspk=r&amounts=2453628&spk=spk#tbend + global txin_amounts, json_db + display = "" + + + + try: + testnet=request.args['testnet'][0] + TN="testnet" + except: + TN="" + + try: + + list_sec, list_hin, list_indexes, list_pubs, list_scriptin, list_outam, list_scriptout, list_amin = [[] for i in range(8)] + + txin_to_use=[] + txouts_nos=[] + txouts_not_empty=[] + for i in request.args: + if i[:4]=='txin' and i[-10:-7]=='use': + txin_to_use.append(i.split('_')[1]) + if i[:4]=='txou' and i.split('_')[2] not in txouts_nos: + p=i.split('_')[1] + no=i.split('_')[2] + txouts_nos.append(no) + + for no in txouts_nos: + if request.args['txout_am_'+no][0]!='' and request.args['txout_am_'+no][0]!='0': + list_outam.append(request.args['txout_am_'+no][0]) + list_scriptout.append(request.args['txout_script_'+no][0]) + + + global addr_to_keys + for h in txin_to_use: + if request.args['txin_'+h+'_add'][0] not in addr_to_keys.keys(): + return "
    No private key for "+request.args['txin_'+h+'_add'][0]+", please dump a wallet containing this address

    Return to Pywallet" + + list_hin.append(h) + list_indexes.append(request.args['txin_'+h+'_n'][0]) + list_scriptin.append(request.args['txin_'+h+'_script'][0]) + list_sec.append(addr_to_keys[request.args['txin_'+h+'_add'][0]][0]) + list_pubs.append(addr_to_keys[request.args['txin_'+h+'_add'][0]][1]) + list_amin.append(request.args['txin_'+h+'_amin'][0]) + + sec=",".join(list_sec) + hashesin=",".join(list_hin) + indexes=",".join(list_indexes) + pubkeys=",".join(list_pubs) + prevspk=",".join(list_scriptin) + amins=",".join(list_amin) + amounts=",".join(list_outam) + spk=",".join(list_scriptout) + + + except: + display += "error" + return display + + secret_key = sec.split(',') + hashes_txin = hashesin.split(',') + indexes_txin = indexes.split(',') + for i in range(len(indexes_txin)): + indexes_txin[i] = int(indexes_txin[i]) + pubkey_txin = pubkeys.split(',') + am_txin = amins.split(',') + prevScriptPubKey = prevspk.split(',') + + amounts_txout = amounts.split(',') + for i in range(len(amounts_txout)): + amounts_txout[i] = int(1e8*float(amounts_txout[i])) + spk_txout = spk.split(',') + + tx = create_transaction(secret_key, hashes_txin, indexes_txin, pubkey_txin, prevScriptPubKey, amounts_txout, spk_txout) + + display += "Inputs: (go to CTTest before)
    " + sum_in = 0 + for i in range(len(hashes_txin)): + try: +# ain = txin_amounts[hashes_txin[i] + ("%d"%indexes_txin[i])] + ain=int(am_txin[i])/1e8 + aaa = ", %.8f BTC"%ain + sum_in += ain + except: + aaa = "" + display += ('%d: %s #%d%s
    ')%(i, hashes_txin[i], indexes_txin[i], hashes_txin[i], indexes_txin[i], aaa) + + display += "

    Outputs:
    " + sum_out = 0 + for i in range(len(spk_txout)): + sum_out += amounts_txout[i]/BTC + display += '%.8f BTC to %s
    '%(amounts_txout[i]/BTC, hash_160_to_bc_address(spk_txout[i].decode('hex'))) + + display += "
    " + display += "
    " + display += "In: %.8f BTC"%sum_in + display += "
    " + display += "Out: %.8f BTC"%sum_out + display += "
    " + display += "Fee: %.8f BTC"%(sum_in-sum_out) + display += "
    " + display += "
    " + display += "
    " + display += ("
    Transaction hash: "+tx[0])
    +			display += "
    " +# display += ("tx_k: "+tx[1]) +# display += "
    " + display += ("Raw transaction: "+tx[2]) + + display += "

    " + + + return display + + def render_POST(self, request): + return self.render_GET(request) + + class WICTTest(resource.Resource): + + def render_GET(self, request): + try: + request.args['testnet'][0] + testnet=True + except: + testnet=False + list_avtx = {} + i = 0 + + try: + for add in request.args['addresses'][0].split(','): + print "Address %d: %s"%(i, add) + list_avtx[add] = bc_address_to_available_tx(add, testnet)[add] + i += 1 + + print(list_avtx) + + display = "" + display += write_avtx(list_avtx, testnet) + except: + display="You must provide at least one address to see the transaction you can spend.
    Like this" + + return display + + def render_POST(self, request): + return self.render_GET(request) + + class WIImport(resource.Resource): def render_GET(self, request): @@ -3149,11 +4213,26 @@ if 'twisted' not in missing_dep: def update_pyw(): if md5_last_pywallet[0] and md5_last_pywallet[1] not in md5_pywallet: - filout = open(pyw_filename, 'w') - filout.write(urllib.urlopen('https://raw.github.com/jackjack-jj/pywallet/master/pywallet.py').read()) - filout.close() - reactor.stop() + dl=urllib.urlopen('https://raw.github.com/jackjack-jj/pywallet/master/pywallet.py').read() + if len(dl)>40 and md5_2(dl)==md5_last_pywallet[1]: + filout = open(pyw_path+"/"+pyw_filename, 'w') + filout.write(dl) + filout.close() + thread.start_new_thread(restart_pywallet, ()) + return "Updated, please wait..." + else: + return "Problem when downloading new version ("+md5_2(dl)+"/"+md5_last_pywallet[1]+")" +def restart_pywallet(): + time.sleep(1) + thread.start_new_thread(start_pywallet, ()) + time.sleep(0.3) + reactor.stop() + +def start_pywallet(): + a=Popen("python "+pyw_path+"/"+pyw_filename+" --web --port "+str(webport)+" --wait 2", shell=True, bufsize=-1, stdout=PIPE).stdout + a.close() + import thread @@ -3163,15 +4242,11 @@ def retrieve_last_pywallet_md5(): global md5_last_pywallet md5_last_pywallet = [True, md5_onlinefile('https://raw.github.com/jackjack-jj/pywallet/master/pywallet.py')] -def zzz(a): - global pywversion - pywversion=a - from optparse import OptionParser if __name__ == '__main__': - md5_pywallet = md5_file(pyw_filename) + md5_pywallet = md5_file(pyw_path+"/"+pyw_filename) thread.start_new_thread(retrieve_last_pywallet_md5, ()) @@ -3243,6 +4318,8 @@ if __name__ == '__main__': parser.add_option("--dont_check_walletversion", dest="dcv", action="store_true", help="don't check if wallet version > %d before running (WARNING: this may break your wallet, be sure you know what you do)"%max_version) + parser.add_option("--wait", dest="nseconds", + help="wait NSECONDS seconds before launch") # parser.add_option("--forcerun", dest="forcerun", @@ -3260,6 +4337,9 @@ if __name__ == '__main__': # if options.forcerun is None: # exit(0) + if options.nseconds: + time.sleep(int(options.nseconds)) + if options.passphrase: passphrase = options.passphrase @@ -3315,7 +4395,13 @@ if __name__ == '__main__': 'Delete': WIDelete(), 'Balance': WIBalance(), 'ChangePP': WIChangePP(), - 'Others': WIOthers() + 'Others': WIOthers(), + 'LoadBalances': WICTTest(), + 'CTTest': WICTTest(), + 'ListTransactions': WICTListTx(), + 'CreateTransaction': WICT(), + 'CT': WICT() + } if options.dcv is not None: