Advertisement
chrisrico

Armory command line anonymizer

Dec 2nd, 2012
531
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.75 KB | None | 0 0
  1. #! /usr/bin/python
  2. import sys
  3. sys.path.append('..')
  4. sys.path.append('.')
  5.  
  6. from armoryengine import *
  7. from sys import argv
  8. from string import Template
  9. import os
  10. import httplib2
  11. import time
  12. import getpass
  13. import json
  14.  
  15. def chooseWallet():
  16.     wlts = [ wlt for wlt in os.listdir(ARMORY_HOME_DIR) if wlt.endswith('.wallet') and not wlt.endswith('_backup.wallet') ]
  17.     if len(wlts) == 1:
  18.         return wlts[0]
  19.     else:
  20.         for i, wlt in enumerate(wlts):
  21.             print '%d) %s' % (i, wlt)
  22.         index = int(raw_input('Open which wallet? [%d-%d] ' % (0, len(wlts)-1)))
  23.         return wlts[index]
  24.  
  25. wltfile = chooseWallet()
  26.  
  27. if wltfile:
  28.     wltfile = os.path.join(ARMORY_HOME_DIR, wltfile)
  29. else:
  30.     print 'No wallet file found in Armory home directory'
  31.  
  32. wlt  = PyBtcWallet().readWalletFile(wltfile)
  33.  
  34. TheBDM.Reset()
  35. TheBDM.setBlocking(newTimeout=60)
  36. TheBDM.registerWallet(wlt.cppWallet)
  37. try:
  38.     TheBDM.setOnlineMode(goOnline=True)
  39. except KeyboardInterrupt:
  40.     exit(1)
  41.  
  42. print 'Spendable balance: %s BTC' % coin2str(wlt.getBalance('Spendable'))
  43.  
  44. total_amt = str2coin(raw_input('Total amount to anonymize? '))
  45. min_amt = str2coin(raw_input('Minimum amount per address? '))
  46. max_amt = str2coin(raw_input('Maximum amount per address? '))
  47. collected = 0
  48. fee = MIN_TX_FEE
  49.  
  50. http = httplib2.Http()
  51. url = Template('https://blockchain.info/api/receive?method=create&address=$address&anonymous=true')
  52. logfile = os.path.join(ARMORY_HOME_DIR, 'anonymize.log')
  53. log = open(logfile, 'w')
  54.  
  55. def getForwardingAddress(my_address):
  56.     response = http.request(url.substitute(address=my_address), 'GET')
  57.     if response[0].status != 200:
  58.         raise Exception('Invalid response: ' + response[0].reason)
  59.     else:
  60.         log.write(response.__str__() + '\n')
  61.         return json.loads(response[1])['input_address']
  62.  
  63. recipValuePairs = []
  64. while collected + fee < total_amt:
  65.     amt = random.randint(min_amt, max_amt)
  66.     if amt > total_amt - collected - fee:
  67.         amt = total_amt - collected - fee
  68.     collected += amt
  69.  
  70.     my_addr = wlt.getNextUnusedAddress()
  71.     fwd_addr = getForwardingAddress(my_addr.getAddrStr())
  72.     wlt.setComment(my_addr.getAddr160(), str('fwd: ' + fwd_addr))
  73.     recip160 = addrStr_to_hash160(fwd_addr)
  74.     recipValuePairs.append( (recip160, amt) )
  75.  
  76. log.close()
  77.  
  78. utxoList = wlt.getTxOutList()
  79. utxoSelect = PySelectCoins(utxoList, collected, fee)
  80.  
  81. totalTxSelect = sum([u.getValue() for u in utxoSelect])
  82. totalChange = totalTxSelect - (collected + fee)
  83. if totalChange > 0:
  84.     change160 = wlt.getNextUnusedAddress().getAddr160()
  85.     recipValuePairs.append( [change160, totalChange])
  86.  
  87. random.shuffle(recipValuePairs)
  88. txdp = PyTxDistProposal().createFromTxOutSelection(utxoSelect, recipValuePairs)
  89.  
  90. print '********************************************************************************'
  91. print 'PLEASE VERIFY THE TRANSACTION DETAILS'
  92. print '********************************************************************************'
  93.  
  94. btcIn  = sum(txdp.inputValues)
  95. btcOut = sum([o.value for o in txdp.pytxObj.outputs])
  96. btcFee = btcIn - btcOut
  97.  
  98. print '   INPUTS:  (%s)' % coin2str(btcIn).strip()
  99. for i,a160 in enumerate(txdp.inAddr20Lists):
  100.    print    '      %s          -->\t%s' % (hash160_to_addrStr(a160[0]), coin2str(txdp.inputValues[i]))
  101.  
  102. print '   OUTPUTS: (%s)' % coin2str(btcOut).strip()
  103. for i,txout in enumerate(txdp.pytxObj.outputs):
  104.    a160 = TxOutScriptExtractAddr160(txout.binScript)
  105.    if wlt.hasAddr(a160):
  106.       print '      %s (change) <--\t%s' % (hash160_to_addrStr(a160), coin2str(txout.value))
  107.    else:
  108.       print '      %s          <--\t%s' % (hash160_to_addrStr(a160), coin2str(txout.value))
  109. print '      %s          <--\t%s' % ('Fee'.ljust(34), coin2str(btcFee))
  110.  
  111. confirm = raw_input('\nDoes this look right?  [y/N]: ')
  112. if not confirm.lower().startswith('y'):
  113.    print 'User did not approve of the transaction.  Aborting.'
  114.    exit(0)
  115.  
  116. dpid = txdp.uniqueB58
  117. txdpfile = os.path.join(ARMORY_HOME_DIR, "armory_%s_.unsigned.tx" % dpid)
  118.  
  119. # If the wallet is watching only, save the unsigned tx
  120. if wlt.watchingOnly:
  121.     print 'Wallet is watching only, saving unsigned tx to %s' % txdpfile
  122.     toSave = txdpfile
  123.     try:
  124.         theFile = open(toSave, 'w')
  125.         theFile.write(txdp.serializeAscii())
  126.         theFile.close()
  127.     except IOError:
  128.         LOGEXCEPT('Failed to save file: %s', toSave)
  129.         pass
  130.     exit(0)
  131.  
  132. # If the wallet is encrypted, get the passphrase
  133. elif wlt.useEncryption:
  134.    print 'Please enter your passphrase to unlock your wallet: '
  135.    for ntries in range(3):
  136.       passwd = SecureBinaryData(getpass.getpass('Wallet Passphrase: '))
  137.       if wlt.verifyPassphrase(passwd):
  138.          break;
  139.  
  140.       print 'Passphrase was incorrect!'
  141.       if ntries==2:
  142.          print 'Wallet could not be unlocked.  Aborting.'
  143.          exit(0)
  144.  
  145.    print 'Correct Passphrase.  Unlocking wallet...'
  146.    wlt.unlock(securePassphrase=passwd)
  147.    passwd.destroy()
  148.  
  149.    try:
  150.       wlt.signTxDistProposal(txdp)
  151.    except WalletLockError:
  152.       print 'Error signing transaction.  Wallet is somehow still locked'
  153.       raise
  154.    except:
  155.       print 'Error signing transaction.  Unknown reason.'
  156.       raise
  157.  
  158.    if not txdp.checkTxHasEnoughSignatures():
  159.       print 'Error signing transaction.  Most likely this is not the correct wallet.'
  160.       exit(0)
  161.  
  162.    outfilename = '.'.join(txdpfile.split('.')[:-2] + ['signed.tx'] )
  163.    outfile = open(outfilename, 'w')
  164.    outfile.write(txdp.serializeAscii())
  165.    outfile.close()
  166.    print '\nSigning was successful!  The signed transaction is located:'
  167.    print '\t', outfilename, '\n'
  168.  
  169.    print ''
  170.    print 'The *.signed.tx file can now be broadcast from any computer running '
  171.    print 'Armory in online mode.  Click "Offline Transactions" and "Broadcast".'
  172.    print ''
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement