def main(): import bitcoin as btc import common import binascii, os from optparse import OptionParser common.nickname = random_nick() #watcher' +binascii.hexlify(os.urandom(4)) common.load_program_config() parser = OptionParser( usage='usage: %prog [options]', description='Runs a webservice which shows the orderbook.') parser.add_option('-H', '--host', action='store', type='string', dest='host', default='localhost', help='hostname or IP to bind to, default=localhost') parser.add_option('-p', '--port', action='store', type='int', dest='port', help='port to listen on, default=62601', default=62601) (options, args) = parser.parse_args() hostport = (options.host, options.port) irc = IRCMessageChannel(common.nickname) taker = GUITaker(irc, hostport) print('starting irc') irc.run()
def main(): parser = OptionParser(usage='usage: %prog [options] [wallet file / fromaccount] [amount] [destaddr]', description='Sends a single payment from a given mixing depth of your ' + 'wallet to an given address using coinjoin and then switches off. Also sends from bitcoinqt. ' + 'Setting amount to zero will do a sweep, where the entire mix depth is emptied') parser.add_option('-f', '--txfee', action='store', type='int', dest='txfee', default=10000, help='miner fee contribution, in satoshis, default=10000') parser.add_option('-w', '--wait-time', action='store', type='float', dest='waittime', help='wait time in seconds to allow orders to arrive, default=5', default=5) parser.add_option('-N', '--makercount', action='store', type='int', dest='makercount', help='how many makers to coinjoin with, default=2', default=2) parser.add_option('-C','--choose-cheapest', action='store_true', dest='choosecheapest', default=False, help='override weightened offers picking and choose cheapest') parser.add_option('-P','--pick-orders', action='store_true', dest='pickorders', default=False, help='manually pick which orders to take. doesn\'t work while sweeping.') parser.add_option('-m', '--mixdepth', action='store', type='int', dest='mixdepth', help='mixing depth to spend from, default=0', default=0) parser.add_option('--yes', action='store_true', dest='answeryes', default=False, help='answer yes to everything') parser.add_option('--rpcwallet', action='store_true', dest='userpcwallet', default=False, help='Use the Bitcoin Core wallet through json rpc, instead of the internal joinmarket ' + 'wallet. Requires blockchain_source=json-rpc') (options, args) = parser.parse_args() if len(args) < 3: parser.error('Needs a wallet, amount and destination address') sys.exit(0) wallet_name = args[0] amount = int(args[1]) destaddr = args[2] load_program_config() addr_valid, errormsg = validate_address(destaddr) if not addr_valid: print 'ERROR: Address invalid. ' + errormsg return common.nickname = random_nick() debug('starting sendpayment') if not options.userpcwallet: wallet = Wallet(wallet_name, options.mixdepth + 1) else: wallet = BitcoinCoreWallet(fromaccount = wallet_name) common.bc_interface.sync_wallet(wallet) irc = IRCMessageChannel(common.nickname) taker = SendPayment(irc, wallet, destaddr, amount, options.makercount, options.txfee, options.waittime, options.mixdepth, options.answeryes, options.choosecheapest, options.pickorders) try: debug('starting irc') irc.run() except: debug('CRASHING, DUMPING EVERYTHING') debug_dump_object(wallet, ['addr_cache', 'keys', 'wallet_name', 'seed']) debug_dump_object(taker) import traceback debug(traceback.format_exc())
def main(): parser = OptionParser(usage='usage: %prog [options] [wallet file / fromaccount] [amount] [destaddr]', description='Sends a single payment from the zero mixing depth of your ' + 'wallet to an given address using coinjoin and then switches off. ' + 'Setting amount to zero will do a sweep, where the entire mix depth is emptied') parser.add_option('-f', '--txfee', action='store', type='int', dest='txfee', default=10000, help='miner fee contribution, in satoshis, default=10000') parser.add_option('-w', '--wait-time', action='store', type='float', dest='waittime', help='wait time in seconds to allow orders to arrive, default=5', default=5) parser.add_option('-N', '--makercount', action='store', type='int', dest='makercount', help='how many makers to coinjoin with, default=2', default=2) parser.add_option('-C','--choose-cheapest', action='store_true', dest='choosecheapest', default=False, help='override weightened offers picking and choose cheapest') parser.add_option('-P','--pick-orders', action='store_true', dest='pickorders', default=False, help='manually pick which orders to take. doesn\'t work while sweeping.') parser.add_option('-m', '--mixdepth', action='store', type='int', dest='mixdepth', help='mixing depth to spend from, default=0', default=0) parser.add_option('--yes', action='store_true', dest='answeryes', default=False, help='answer yes to everything') parser.add_option('--rpcwallet', action='store_true', dest='userpcwallet', default=False, help='Use the Bitcoin Core wallet through json rpc, instead of the internal joinmarket ' + 'wallet. Requires blockchain_source=json-rpc') (options, args) = parser.parse_args() if len(args) < 3: parser.error('Needs a wallet, amount and destination address') sys.exit(0) wallet_name = args[0] amount = int(args[1]) destaddr = args[2] load_program_config() addr_valid, errormsg = validate_address(destaddr) if not addr_valid: print 'ERROR: Address invalid. ' + errormsg return common.nickname = random_nick() debug('starting sendpayment') if not options.userpcwallet: wallet = Wallet(wallet_name, options.mixdepth + 1) else: wallet = BitcoinCoreWallet(fromaccount = wallet_name) common.bc_interface.sync_wallet(wallet) irc = IRCMessageChannel(common.nickname) taker = SendPayment(irc, wallet, destaddr, amount, options.makercount, options.txfee, options.waittime, options.mixdepth, options.answeryes, options.choosecheapest, options.pickorders) try: debug('starting irc') irc.run() except: debug('CRASHING, DUMPING EVERYTHING') debug_dump_object(wallet, ['addr_cache', 'keys', 'wallet_name', 'seed']) debug_dump_object(taker) import traceback debug(traceback.format_exc())
def main(): parser = OptionParser(usage='usage: %prog [options] [wallet file / seed] [amount] [destaddr]', description='Sends a payment from your wallet to an given address' + ' using coinjoin. First acts as a maker, announcing an order and ' + 'waiting for someone to fill it. After a set period of time, gives' + ' up waiting and acts as a taker and coinjoins any remaining coins') parser.add_option('-f', '--txfee', action='store', type='int', dest='txfee', default=10000, help='miner fee contribution, in satoshis, default=10000') parser.add_option('-N', '--makercount', action='store', type='int', dest='makercount', help='how many makers to coinjoin with when taking liquidity, default=2', default=2) parser.add_option('-w', '--wait-time', action='store', type='float', dest='waittime', help='wait time in hours as a maker before becoming a taker, default=8', default=8) parser.add_option('-c', '--cjfee', action='store', type='int', dest='cjfee', help='coinjoin fee asked for when being a maker, in satoshis per order filled, default=50000', default=50000) parser.add_option('-m', '--mixdepth', action='store', type='int', dest='mixdepth', help='mixing depth to spend from, default=0', default=0) (options, args) = parser.parse_args() if len(args) < 3: parser.error('Needs a seed, amount and destination address') sys.exit(0) seed = args[0] amount = int(args[1]) destaddr = args[2] load_program_config() addr_valid, errormsg = validate_address(destaddr) if not addr_valid: print 'ERROR: Address invalid. ' + errormsg return waittime = timedelta(hours=options.waittime).total_seconds() print 'txfee=%d cjfee=%d waittime=%s makercount=%d' % (options.txfee, options.cjfee, str(timedelta(hours=options.waittime)), options.makercount) wallet = Wallet(seed, options.mixdepth + 1) common.bc_interface.sync_wallet(wallet) available_balance = wallet.get_balance_by_mixdepth()[options.mixdepth] if available_balance < amount: print 'not enough money at mixdepth=%d, exiting' % (options.mixdepth) return common.nickname = random_nick() debug('Running patient sender of a payment') irc = IRCMessageChannel(common.nickname) bot = PatientSendPayment(irc, wallet, destaddr, amount, options.makercount, options.txfee, options.cjfee, waittime, options.mixdepth) try: irc.run() except: debug('CRASHING, DUMPING EVERYTHING') debug_dump_object(wallet, ['addr_cache', 'keys', 'seed']) debug_dump_object(taker) import traceback traceback.print_exc()
def main(): import bitcoin as btc import common import binascii, os common.nickname =random_nick() #watcher' +binascii.hexlify(os.urandom(4)) common.load_program_config() irc = IRCMessageChannel(common.nickname) taker = GUITaker(irc) print 'starting irc' irc.run()
def main(): import bitcoin as btc import common import binascii, os common.nickname = random_nick() #watcher' +binascii.hexlify(os.urandom(4)) common.load_program_config() irc = IRCMessageChannel(common.nickname) taker = GUITaker(irc) print 'starting irc' irc.run()
def main(): parser = OptionParser(usage='usage: %prog [options] [wallet file / seed] [amount] [destaddr]', description='Sends a single payment from the zero mixing depth of your ' + 'wallet to an given address using coinjoin and then switches off. ' + 'Setting amount to zero will do a sweep, where the entire mix depth is emptied') parser.add_option('-f', '--txfee', action='store', type='int', dest='txfee', default=10000, help='miner fee contribution, in satoshis, default=10000') parser.add_option('-w', '--wait-time', action='store', type='float', dest='waittime', help='wait time in seconds to allow orders to arrive, default=5', default=5) parser.add_option('-N', '--makercount', action='store', type='int', dest='makercount', help='how many makers to coinjoin with, default=2', default=2) parser.add_option('-m', '--mixdepth', action='store', type='int', dest='mixdepth', help='mixing depth to spend from, default=0', default=0) parser.add_option('--yes', action='store_true', dest='answeryes', default=False, help='answer yes to everything') (options, args) = parser.parse_args() if len(args) < 3: parser.error('Needs a seed, amount and destination address') sys.exit(0) seed = args[0] amount = int(args[1]) destaddr = args[2] load_program_config() addr_valid, errormsg = validate_address(destaddr) if not addr_valid: print 'ERROR: Address invalid. ' + errormsg return common.nickname = random_nick() debug('starting sendpayment') import binascii, os wallet = Wallet(seed, options.mixdepth + 1) common.bc_interface.sync_wallet(wallet) wallet.print_debug_wallet_info() irc = IRCMessageChannel(common.nickname) taker = SendPayment(irc, wallet, destaddr, amount, options.makercount, options.txfee, options.waittime, options.mixdepth, options.answeryes) try: debug('starting irc') irc.run() except: debug('CRASHING, DUMPING EVERYTHING') debug('wallet seed = ' + seed) debug_dump_object(wallet, ['addr_cache', 'keys', 'seed']) debug_dump_object(taker) import traceback debug(traceback.format_exc())
def main(): import bitcoin as btc import common import binascii, os from optparse import OptionParser common.nickname =random_nick() #watcher' +binascii.hexlify(os.urandom(4)) common.load_program_config() parser = OptionParser(usage='usage: %prog [options]', description='Runs a webservice which shows the orderbook.') parser.add_option('-H', '--host', action='store', type='string', dest='host', default='localhost', help='hostname or IP to bind to, default=localhost') parser.add_option('-p', '--port', action='store', type='int', dest='port', help='port to listen on, default=62601', default=62601) (options, args) = parser.parse_args() hostport = (options.host, options.port) irc = IRCMessageChannel(common.nickname) taker = GUITaker(irc, hostport) print('starting irc') irc.run()
def main(): parser = OptionParser(usage='usage: %prog [options] [wallet file / seed] [destaddr...]', description='Sends bitcoins to many different addresses using coinjoin in' ' an attempt to break the link between them. Sending to multiple ' ' addresses is highly recommended for privacy. This tumbler can' ' be configured to ask for more address mid-run, giving the user' ' a chance to click `Generate New Deposit Address` on whatever service' ' they are using.') parser.add_option('-m', '--mixdepthsource', type='int', dest='mixdepthsrc', help='mixing depth to spend from, default=0', default=0) parser.add_option('-f', '--txfee', type='int', dest='txfee', default=10000, help='miner fee contribution, in satoshis, default=10000') parser.add_option('-x', '--maxcjfee', type='float', dest='maxcjfee', default=0.03, help='maximum coinjoin fee the tumbler is willing to pay to a single market maker. default=0.03 (3%)') parser.add_option('-a', '--addrask', type='int', dest='addrask', default=2, help='How many more addresses to ask for in the terminal. Should ' 'be similar to --txcountparams. default=2') parser.add_option('-N', '--makercountrange', type='float', nargs=2, action='store', dest='makercountrange', help='Input the range of makers to use. e.g. 3-5 will random use between ' '3 and 5 makers inclusive, default=3 4', default=(3, 1)) parser.add_option('-M', '--mixdepthcount', type='int', dest='mixdepthcount', help='How many mixing depths to mix through', default=4) parser.add_option('-c', '--txcountparams', type='float', nargs=2, dest='txcountparams', default=(5, 1), help='The number of transactions to take coins from one mixing depth to the next, it is' ' randomly chosen following a normal distribution. Should be similar to --addrask. ' 'This option controlls the parameters of that normal curve. (mean, standard deviation). default=(3, 1)') parser.add_option('--amountpower', type='float', dest='amountpower', default=100.0, help='The output amounts follow a power law distribution, this is the power, default=100.0') parser.add_option('-l', '--timelambda', type='float', dest='timelambda', default=20, help='Average the number of minutes to wait between transactions. Randomly chosen ' ' following an exponential distribution, which describes the time between uncorrelated' ' events. default=20') parser.add_option('-w', '--wait-time', action='store', type='float', dest='waittime', help='wait time in seconds to allow orders to arrive, default=5', default=5) parser.add_option('-s', '--mincjamount', type='float', dest='mincjamount', default=0.0001, help='minimum coinjoin amount in transaction') (options, args) = parser.parse_args() #TODO somehow implement a lower limit if len(args) < 1: parser.error('Needs a seed') sys.exit(0) seed = args[0] destaddrs = args[1:] common.load_program_config() for addr in destaddrs: addr_valid, errormsg = validate_address(addr) if not addr_valid: print 'ERROR: Address ' + addr + ' invalid. ' + errormsg return if len(destaddrs) + options.addrask <= 1: print '='*50 print 'WARNING: You are only using one destination address' print 'this is very bad for privacy' print '='*50 print str(options) tx_list = generate_tumbler_tx(destaddrs, options) if not tx_list: return tx_list2 = copy.deepcopy(tx_list) tx_dict = {} for tx in tx_list2: srcmixdepth = tx['srcmixdepth'] tx.pop('srcmixdepth') if srcmixdepth not in tx_dict: tx_dict[srcmixdepth] = [] tx_dict[srcmixdepth].append(tx) dbg_tx_list = [] for srcmixdepth, txlist in tx_dict.iteritems(): dbg_tx_list.append({'srcmixdepth': srcmixdepth, 'tx': txlist}) print 'tumbler transaction list' pprint(dbg_tx_list) total_wait = sum([tx['wait'] for tx in tx_list]) print 'waits in total for ' + str(len(tx_list)) + ' blocks and ' + str(total_wait) + ' minutes' total_block_and_wait = len(tx_list)*10 + total_wait print('estimated time taken ' + str(total_block_and_wait) + ' minutes or ' + str(round(total_block_and_wait/60.0, 2)) + ' hours') ret = raw_input('tumble with these tx? (y/n):') if ret[0] != 'y': return #a couple of modes #im-running-from-the-nsa, takes about 80 hours, costs a lot #python tumbler.py -a 10 -N 10 5 -c 10 5 -l 50 -M 10 seed 1xxx # #quick and cheap, takes about 90 minutes #python tumbler.py -N 2 1 -c 3 0.001 -l 10 -M 3 -a 1 seed 1xxx # #default, good enough for most, takes about 5 hours #python tumbler.py seed 1xxx # #for quick testing #python tumbler.py -N 2 1 -c 3 0.001 -l 0.1 -M 3 -a 0 seed 1xxx 1yyy wallet = Wallet(seed, max_mix_depth = options.mixdepthsrc + options.mixdepthcount) common.bc_interface.sync_wallet(wallet) common.nickname = random_nick() debug('starting tumbler') irc = IRCMessageChannel(common.nickname) tumbler = Tumbler(irc, wallet, tx_list, options.txfee, options.maxcjfee, options.mincjamount) try: debug('connecting to irc') irc.run() except: debug('CRASHING, DUMPING EVERYTHING') debug_dump_object(wallet, ['addr_cache', 'keys', 'seed']) debug_dump_object(tumbler) import traceback debug(traceback.format_exc())
import time, os, binascii, sys, datetime import pprint data_dir = os.path.dirname(os.path.realpath(__file__)) sys.path.insert(0, os.path.join(data_dir, 'lib')) from maker import * from irc import IRCMessageChannel, random_nick import bitcoin as btc import common, blockchaininterface from socket import gethostname txfee = 1000 cjfee = '0.002' # 0.2% fee nickname = random_nick() nickserv_password = '' minsize = int(1.2 * txfee / float(cjfee)) #minimum size is such that you always net profit at least 20% of the miner fee mix_levels = 5 #is a maker for the purposes of generating a yield from held # bitcoins without ruining privacy for the taker, the taker could easily check # the history of the utxos this bot sends, so theres not much incentive # to ruin the privacy for barely any more yield #sell-side algorithm: #add up the value of each utxo for each mixing depth, # announce a relative-fee order of the highest balance #spent from utxos that try to make the highest balance even higher # so try to keep coins concentrated in one mixing depth
def main(): parser = OptionParser(usage='usage: %prog [options] [wallet file] [destaddr(s)...]', description='Sends bitcoins to many different addresses using coinjoin in' ' an attempt to break the link between them. Sending to multiple ' ' addresses is highly recommended for privacy. This tumbler can' ' be configured to ask for more address mid-run, giving the user' ' a chance to click `Generate New Deposit Address` on whatever service' ' they are using.') parser.add_option('-m', '--mixdepthsource', type='int', dest='mixdepthsrc', help='mixing depth to spend from, default=0', default=0) parser.add_option('-f', '--txfee', type='int', dest='txfee', default=10000, help='miner fee contribution, in satoshis, default=10000') parser.add_option('-x', '--maxcjfee', type='float', dest='maxcjfee', nargs=2, default=(0.01, 10000), help='maximum coinjoin fee and bitcoin value the tumbler is ' 'willing to pay to a single market maker. Both values need to be exceeded, so if ' 'the fee is 30% but only 500satoshi is paid the tx will go ahead. default=0.01, 10000 (1%, 10000satoshi)') parser.add_option('-a', '--addrcount', type='int', dest='addrcount', default=3, help='How many destination addresses in total should be used. If not enough are given' ' as command line arguments, the script will ask for more, default=3') parser.add_option('-N', '--makercountrange', type='float', nargs=2, action='store', dest='makercountrange', help='Input the mean and spread of number of makers to use. e.g. 3 1.5 will be a normal distribution ' 'with mean 3 and standard deveation 1.5 inclusive, default=3 1.5', default=(3, 1.5)) parser.add_option('-M', '--mixdepthcount', type='int', dest='mixdepthcount', help='How many mixing depths to mix through', default=4) parser.add_option('-c', '--txcountparams', type='float', nargs=2, dest='txcountparams', default=(4, 1), help='The number of transactions to take coins from one mixing depth to the next, it is' ' randomly chosen following a normal distribution. Should be similar to --addrask. ' 'This option controlls the parameters of that normal curve. (mean, standard deviation). default=(4, 1)') parser.add_option('--amountpower', type='float', dest='amountpower', default=100.0, help='The output amounts follow a power law distribution, this is the power, default=100.0') parser.add_option('-l', '--timelambda', type='float', dest='timelambda', default=20, help='Average the number of minutes to wait between transactions. Randomly chosen ' ' following an exponential distribution, which describes the time between uncorrelated' ' events. default=20') parser.add_option('-w', '--wait-time', action='store', type='float', dest='waittime', help='wait time in seconds to allow orders to arrive, default=5', default=5) parser.add_option('-s', '--mincjamount', type='int', dest='mincjamount', default=100000, help='minimum coinjoin amount in transaction in satoshi, default 100k') (options, args) = parser.parse_args() #TODO somehow implement a lower limit if len(args) < 1: parser.error('Needs a wallet file') sys.exit(0) wallet_file = args[0] destaddrs = args[1:] common.load_program_config() for addr in destaddrs: addr_valid, errormsg = validate_address(addr) if not addr_valid: print 'ERROR: Address ' + addr + ' invalid. ' + errormsg return if len(destaddrs) > options.addrcount: options.addrcount = len(destaddrs) if options.addrcount+1 > options.mixdepthcount: print 'not enough mixing depths to pay to all destination addresses, increasing mixdepthcount' options.mixdepthcount = options.addrcount+1 if options.addrcount <= 1: print '='*50 print 'WARNING: You are only using one destination address' print 'this is very bad for privacy' print '='*50 print str(options) tx_list = generate_tumbler_tx(destaddrs, options) if not tx_list: return tx_list2 = copy.deepcopy(tx_list) tx_dict = {} for tx in tx_list2: srcmixdepth = tx['srcmixdepth'] tx.pop('srcmixdepth') if srcmixdepth not in tx_dict: tx_dict[srcmixdepth] = [] tx_dict[srcmixdepth].append(tx) dbg_tx_list = [] for srcmixdepth, txlist in tx_dict.iteritems(): dbg_tx_list.append({'srcmixdepth': srcmixdepth, 'tx': txlist}) debug('tumbler transaction list') pprint(dbg_tx_list) total_wait = sum([tx['wait'] for tx in tx_list]) print 'creates ' + str(len(tx_list)) + ' transactions in total' print 'waits in total for ' + str(len(tx_list)) + ' blocks and ' + str(total_wait) + ' minutes' total_block_and_wait = len(tx_list)*10 + total_wait print('estimated time taken ' + str(total_block_and_wait) + ' minutes or ' + str(round(total_block_and_wait/60.0, 2)) + ' hours') ret = raw_input('tumble with these tx? (y/n):') if ret[0] != 'y': return #NOTE: possibly out of date documentation #a couple of modes #im-running-from-the-nsa, takes about 80 hours, costs a lot #python tumbler.py -a 10 -N 10 5 -c 10 5 -l 50 -M 10 wallet_file 1xxx # #quick and cheap, takes about 90 minutes #python tumbler.py -N 2 1 -c 3 0.001 -l 10 -M 3 -a 1 wallet_file 1xxx # #default, good enough for most, takes about 5 hours #python tumbler.py wallet_file 1xxx # #for quick testing #python tumbler.py -N 2 1 -c 3 0.001 -l 0.1 -M 3 -a 0 wallet_file 1xxx 1yyy wallet = Wallet(wallet_file, max_mix_depth = options.mixdepthsrc + options.mixdepthcount) common.bc_interface.sync_wallet(wallet) #check if there are actually any coins at the mixdepthsrc level #if not, allow user to start at minimum used level used_depths = [k for k,v in wallet.get_utxos_by_mixdepth().iteritems() if v != {}] if options.mixdepthsrc not in used_depths: ret = raw_input("no coins in chosen src level. Use lowest possible level? (y/n):") if ret[0] !='y': return options.mixdepthsrc = sorted(used_depths.keys())[0] print "starting with depth: " + str(options.mixdepthsrc) wallet = Wallet(wallet_file,max_mix_depth = options.mixdepthsrc + options.mixdepthcount) common.bc_interface.sync_wallet(wallet) common.nickname = random_nick() debug('starting tumbler') irc = IRCMessageChannel(common.nickname) tumbler = Tumbler(irc, wallet, tx_list, options.txfee, options.maxcjfee, options.mincjamount) try: debug('connecting to irc') irc.run() except: debug('CRASHING, DUMPING EVERYTHING') debug_dump_object(wallet, ['addr_cache', 'keys', 'seed']) debug_dump_object(tumbler) debug_dump_object(tumbler.cjtx) import traceback debug(traceback.format_exc())
def main(): parser = OptionParser( usage= 'usage: %prog [options] [auth utxo] [cjamount] [cjaddr] [changeaddr] [utxos..]', description= 'Creates an unsigned coinjoin transaction. Outputs a partially signed transaction ' + 'hex string. The user must sign their inputs independently and broadcast them. The JoinMarket' + ' protocol requires the taker to have a single p2pk UTXO input to use to authenticate the ' + ' encrypted messages. For this reason you must pass auth utxo and the corresponding private key' ) #for cjamount=0 do a sweep, and ignore change address parser.add_option( '-f', '--txfee', action='store', type='int', dest='txfee', default=10000, help='miner fee contribution, in satoshis, default=10000') parser.add_option( '-w', '--wait-time', action='store', type='float', dest='waittime', help='wait time in seconds to allow orders to arrive, default=5', default=5) parser.add_option('-N', '--makercount', action='store', type='int', dest='makercount', help='how many makers to coinjoin with, default=2', default=2) parser.add_option( '-C', '--choose-cheapest', action='store_true', dest='choosecheapest', default=False, help='override weightened offers picking and choose cheapest') parser.add_option( '-P', '--pick-orders', action='store_true', dest='pickorders', default=False, help='manually pick which orders to take. doesn\'t work while sweeping.' ) parser.add_option('--yes', action='store_true', dest='answeryes', default=False, help='answer yes to everything') #TODO implement #parser.add_option('-n', '--no-network', action='store_true', dest='nonetwork', default=False, # help='dont query the blockchain interface, instead user must supply value of UTXOs on ' + # ' command line in the format txid:output/value-in-satoshi') (options, args) = parser.parse_args() if len(args) < 3: parser.error('Needs a wallet, amount and destination address') sys.exit(0) auth_utxo = args[0] cjamount = int(args[1]) destaddr = args[2] changeaddr = args[3] cold_utxos = args[4:] common.load_program_config() addr_valid1, errormsg1 = validate_address(destaddr) #if amount = 0 dont bother checking changeaddr so user can write any junk if cjamount != 0: addr_valid2, errormsg2 = validate_address(changeaddr) else: addr_valid2 = True if not addr_valid1 or not addr_valid2: if not addr_valid1: print 'ERROR: Address invalid. ' + errormsg1 else: print 'ERROR: Address invalid. ' + errormsg2 return all_utxos = [auth_utxo] + cold_utxos query_result = common.bc_interface.query_utxo_set(all_utxos) if None in query_result: print query_result utxo_data = {} for utxo, data in zip(all_utxos, query_result): utxo_data[utxo] = {'address': data['address'], 'value': data['value']} auth_privkey = raw_input('input private key for ' + utxo_data[auth_utxo]['address'] + ' :') if utxo_data[auth_utxo]['address'] != btc.privtoaddr( auth_privkey, common.get_p2pk_vbyte()): print 'ERROR: privkey does not match auth utxo' return chooseOrdersFunc = None if options.pickorders and amount != 0: #cant use for sweeping chooseOrdersFunc = pick_order elif options.choosecheapest: chooseOrdersFunc = cheapest_order_choose else: #choose randomly (weighted) chooseOrdersFunc = weighted_order_choose common.nickname = random_nick() debug('starting sendpayment') class UnsignedTXWallet(common.AbstractWallet): def get_key_from_addr(self, addr): debug('getting privkey of ' + addr) if btc.privtoaddr(auth_privkey, common.get_p2pk_vbyte()) != addr: raise RuntimeError('privkey doesnt match given address') return auth_privkey wallet = UnsignedTXWallet() irc = IRCMessageChannel(common.nickname) taker = CreateUnsignedTx(irc, wallet, auth_utxo, cjamount, destaddr, changeaddr, utxo_data, options, chooseOrdersFunc) try: debug('starting irc') irc.run() except: debug('CRASHING, DUMPING EVERYTHING') debug_dump_object(wallet, ['addr_cache', 'keys', 'wallet_name', 'seed']) debug_dump_object(taker) import traceback debug(traceback.format_exc())
def main(): parser = OptionParser( usage="usage: %prog [options] [wallet file / fromaccount] [amount] [destaddr]", description="Sends a single payment from a given mixing depth of your " + "wallet to an given address using coinjoin and then switches off. Also sends from bitcoinqt. " + "Setting amount to zero will do a sweep, where the entire mix depth is emptied", ) parser.add_option( "-f", "--txfee", action="store", type="int", dest="txfee", default=30000, help="total miner fee in satoshis, default=30000", ) parser.add_option( "-w", "--wait-time", action="store", type="float", dest="waittime", help="wait time in seconds to allow orders to arrive, default=5", default=5, ) parser.add_option( "-N", "--makercount", action="store", type="int", dest="makercount", help="how many makers to coinjoin with, default=2", default=2, ) parser.add_option( "-C", "--choose-cheapest", action="store_true", dest="choosecheapest", default=False, help="override weightened offers picking and choose cheapest", ) parser.add_option( "-P", "--pick-orders", action="store_true", dest="pickorders", default=False, help="manually pick which orders to take. doesn't work while sweeping.", ) parser.add_option( "-m", "--mixdepth", action="store", type="int", dest="mixdepth", help="mixing depth to spend from, default=0", default=0, ) parser.add_option("--yes", action="store_true", dest="answeryes", default=False, help="answer yes to everything") parser.add_option( "--rpcwallet", action="store_true", dest="userpcwallet", default=False, help="Use the Bitcoin Core wallet through json rpc, instead of the internal joinmarket " + "wallet. Requires blockchain_source=json-rpc", ) (options, args) = parser.parse_args() if len(args) < 3: parser.error("Needs a wallet, amount and destination address") sys.exit(0) wallet_name = args[0] amount = int(args[1]) destaddr = args[2] load_program_config() addr_valid, errormsg = validate_address(destaddr) if not addr_valid: print "ERROR: Address invalid. " + errormsg return chooseOrdersFunc = None if options.pickorders and amount != 0: # cant use for sweeping chooseOrdersFunc = pick_order elif options.choosecheapest: chooseOrdersFunc = cheapest_order_choose else: # choose randomly (weighted) chooseOrdersFunc = weighted_order_choose common.nickname = random_nick() debug("starting sendpayment") if not options.userpcwallet: wallet = Wallet(wallet_name, options.mixdepth + 1) else: wallet = BitcoinCoreWallet(fromaccount=wallet_name) common.bc_interface.sync_wallet(wallet) irc = IRCMessageChannel(common.nickname) taker = SendPayment( irc, wallet, destaddr, amount, options.makercount, options.txfee, options.waittime, options.mixdepth, options.answeryes, chooseOrdersFunc, ) try: debug("starting irc") irc.run() except: debug("CRASHING, DUMPING EVERYTHING") debug_dump_object(wallet, ["addr_cache", "keys", "wallet_name", "seed"]) debug_dump_object(taker) import traceback debug(traceback.format_exc())
def main(): parser = OptionParser( usage='usage: %prog [options] [wallet file] [destaddr(s)...]', description= 'Sends bitcoins to many different addresses using coinjoin in' ' an attempt to break the link between them. Sending to multiple ' ' addresses is highly recommended for privacy. This tumbler can' ' be configured to ask for more address mid-run, giving the user' ' a chance to click `Generate New Deposit Address` on whatever service' ' they are using.') parser.add_option('-m', '--mixdepthsource', type='int', dest='mixdepthsrc', help='mixing depth to spend from, default=0', default=0) parser.add_option( '-f', '--txfee', type='int', dest='txfee', default=10000, help='miner fee contribution, in satoshis, default=10000') parser.add_option( '-x', '--maxcjfee', type='float', dest='maxcjfee', default=0.01, help= 'maximum coinjoin fee the tumbler is willing to pay to a single market maker. default=0.01 (1%)' ) parser.add_option( '-a', '--addrask', type='int', dest='addrask', default=2, help='How many more addresses to ask for in the terminal. Should ' 'be similar to --txcountparams. default=2') parser.add_option( '-N', '--makercountrange', type='float', nargs=2, action='store', dest='makercountrange', help= 'Input the mean and spread of number of makers to use. e.g. 3 1.5 will be a normal distribution ' 'with mean 3 and standard deveation 1.5 inclusive, default=3 1.5', default=(3, 1.5)) parser.add_option('-M', '--mixdepthcount', type='int', dest='mixdepthcount', help='How many mixing depths to mix through', default=4) parser.add_option( '-c', '--txcountparams', type='float', nargs=2, dest='txcountparams', default=(5, 1), help= 'The number of transactions to take coins from one mixing depth to the next, it is' ' randomly chosen following a normal distribution. Should be similar to --addrask. ' 'This option controlls the parameters of that normal curve. (mean, standard deviation). default=(3, 1)' ) parser.add_option( '--amountpower', type='float', dest='amountpower', default=100.0, help= 'The output amounts follow a power law distribution, this is the power, default=100.0' ) parser.add_option( '-l', '--timelambda', type='float', dest='timelambda', default=20, help= 'Average the number of minutes to wait between transactions. Randomly chosen ' ' following an exponential distribution, which describes the time between uncorrelated' ' events. default=20') parser.add_option( '-w', '--wait-time', action='store', type='float', dest='waittime', help='wait time in seconds to allow orders to arrive, default=5', default=5) parser.add_option( '-s', '--mincjamount', type='int', dest='mincjamount', default=100000, help='minimum coinjoin amount in transaction in satoshi, default 100k') (options, args) = parser.parse_args() #TODO somehow implement a lower limit if len(args) < 1: parser.error('Needs a wallet file') sys.exit(0) wallet_file = args[0] destaddrs = args[1:] common.load_program_config() for addr in destaddrs: addr_valid, errormsg = validate_address(addr) if not addr_valid: print 'ERROR: Address ' + addr + ' invalid. ' + errormsg return if len(destaddrs) + options.addrask <= 1: print '=' * 50 print 'WARNING: You are only using one destination address' print 'this is very bad for privacy' print '=' * 50 print str(options) tx_list = generate_tumbler_tx(destaddrs, options) if not tx_list: return tx_list2 = copy.deepcopy(tx_list) tx_dict = {} for tx in tx_list2: srcmixdepth = tx['srcmixdepth'] tx.pop('srcmixdepth') if srcmixdepth not in tx_dict: tx_dict[srcmixdepth] = [] tx_dict[srcmixdepth].append(tx) dbg_tx_list = [] for srcmixdepth, txlist in tx_dict.iteritems(): dbg_tx_list.append({'srcmixdepth': srcmixdepth, 'tx': txlist}) debug('tumbler transaction list') pprint(dbg_tx_list) total_wait = sum([tx['wait'] for tx in tx_list]) print 'waits in total for ' + str( len(tx_list)) + ' blocks and ' + str(total_wait) + ' minutes' total_block_and_wait = len(tx_list) * 10 + total_wait print('estimated time taken ' + str(total_block_and_wait) + ' minutes or ' + str(round(total_block_and_wait / 60.0, 2)) + ' hours') ret = raw_input('tumble with these tx? (y/n):') if ret[0] != 'y': return #NOTE: possibly out of date documentation #a couple of modes #im-running-from-the-nsa, takes about 80 hours, costs a lot #python tumbler.py -a 10 -N 10 5 -c 10 5 -l 50 -M 10 wallet_file 1xxx # #quick and cheap, takes about 90 minutes #python tumbler.py -N 2 1 -c 3 0.001 -l 10 -M 3 -a 1 wallet_file 1xxx # #default, good enough for most, takes about 5 hours #python tumbler.py wallet_file 1xxx # #for quick testing #python tumbler.py -N 2 1 -c 3 0.001 -l 0.1 -M 3 -a 0 wallet_file 1xxx 1yyy wallet = Wallet(wallet_file, max_mix_depth=options.mixdepthsrc + options.mixdepthcount) common.bc_interface.sync_wallet(wallet) common.nickname = random_nick() debug('starting tumbler') irc = IRCMessageChannel(common.nickname) tumbler = Tumbler(irc, wallet, tx_list, options.txfee, options.maxcjfee, options.mincjamount) try: debug('connecting to irc') irc.run() except: debug('CRASHING, DUMPING EVERYTHING') debug_dump_object(wallet, ['addr_cache', 'keys', 'seed']) debug_dump_object(tumbler) import traceback debug(traceback.format_exc())
def main(): parser = OptionParser( usage='usage: %prog [options] [wallet file / seed] [amount] [destaddr]', description='Sends a single payment from the zero mixing depth of your ' + 'wallet to an given address using coinjoin and then switches off. ' + 'Setting amount to zero will do a sweep, where the entire mix depth is emptied' ) parser.add_option( '-f', '--txfee', action='store', type='int', dest='txfee', default=10000, help='miner fee contribution, in satoshis, default=10000') parser.add_option( '-w', '--wait-time', action='store', type='float', dest='waittime', help='wait time in seconds to allow orders to arrive, default=5', default=5) parser.add_option('-N', '--makercount', action='store', type='int', dest='makercount', help='how many makers to coinjoin with, default=2', default=2) parser.add_option('-m', '--mixdepth', action='store', type='int', dest='mixdepth', help='mixing depth to spend from, default=0', default=0) parser.add_option('--yes', action='store_true', dest='answeryes', default=False, help='answer yes to everything') (options, args) = parser.parse_args() if len(args) < 3: parser.error('Needs a seed, amount and destination address') sys.exit(0) seed = args[0] amount = int(args[1]) destaddr = args[2] load_program_config() addr_valid, errormsg = validate_address(destaddr) if not addr_valid: print 'ERROR: Address invalid. ' + errormsg return common.nickname = random_nick() debug('starting sendpayment') import binascii, os wallet = Wallet(seed, options.mixdepth + 1) common.bc_interface.sync_wallet(wallet) wallet.print_debug_wallet_info() irc = IRCMessageChannel(common.nickname) taker = SendPayment(irc, wallet, destaddr, amount, options.makercount, options.txfee, options.waittime, options.mixdepth, options.answeryes) try: debug('starting irc') irc.run() except: debug('CRASHING, DUMPING EVERYTHING') debug('wallet seed = ' + seed) debug_dump_object(wallet, ['addr_cache', 'keys', 'seed']) debug_dump_object(taker) import traceback debug(traceback.format_exc())
def main(): parser = OptionParser(usage='usage: %prog [options] [auth utxo] [cjamount] [cjaddr] [changeaddr] [utxos..]', description='Creates an unsigned coinjoin transaction. Outputs a partially signed transaction ' + 'hex string. The user must sign their inputs independently and broadcast them. The JoinMarket' + ' protocol requires the taker to have a single p2pk UTXO input to use to authenticate the ' + ' encrypted messages. For this reason you must pass auth utxo and the corresponding private key') #for cjamount=0 do a sweep, and ignore change address parser.add_option('-f', '--txfee', action='store', type='int', dest='txfee', default=10000, help='total miner fee in satoshis, default=10000') parser.add_option('-w', '--wait-time', action='store', type='float', dest='waittime', help='wait time in seconds to allow orders to arrive, default=5', default=5) parser.add_option('-N', '--makercount', action='store', type='int', dest='makercount', help='how many makers to coinjoin with, default=2', default=2) parser.add_option('-C','--choose-cheapest', action='store_true', dest='choosecheapest', default=False, help='override weightened offers picking and choose cheapest') parser.add_option('-P','--pick-orders', action='store_true', dest='pickorders', default=False, help='manually pick which orders to take. doesn\'t work while sweeping.') parser.add_option('--yes', action='store_true', dest='answeryes', default=False, help='answer yes to everything') #TODO implement #parser.add_option('-n', '--no-network', action='store_true', dest='nonetwork', default=False, # help='dont query the blockchain interface, instead user must supply value of UTXOs on ' + # ' command line in the format txid:output/value-in-satoshi') (options, args) = parser.parse_args() if len(args) < 3: parser.error('Needs a wallet, amount and destination address') sys.exit(0) auth_utxo = args[0] cjamount = int(args[1]) destaddr = args[2] changeaddr = args[3] cold_utxos = args[4:] common.load_program_config() addr_valid1, errormsg1 = validate_address(destaddr) #if amount = 0 dont bother checking changeaddr so user can write any junk if cjamount != 0: addr_valid2, errormsg2 = validate_address(changeaddr) else: addr_valid2 = True if not addr_valid1 or not addr_valid2: if not addr_valid1: print 'ERROR: Address invalid. ' + errormsg1 else: print 'ERROR: Address invalid. ' + errormsg2 return all_utxos = [auth_utxo] + cold_utxos query_result = common.bc_interface.query_utxo_set(all_utxos) if None in query_result: print query_result utxo_data = {} for utxo, data in zip(all_utxos, query_result): utxo_data[utxo] = {'address': data['address'], 'value': data['value']} auth_privkey = raw_input('input private key for ' + utxo_data[auth_utxo]['address'] + ' :') if utxo_data[auth_utxo]['address'] != btc.privtoaddr(auth_privkey, common.get_p2pk_vbyte()): print 'ERROR: privkey does not match auth utxo' return chooseOrdersFunc = None if options.pickorders and amount != 0: #cant use for sweeping chooseOrdersFunc = pick_order elif options.choosecheapest: chooseOrdersFunc = cheapest_order_choose else: #choose randomly (weighted) chooseOrdersFunc = weighted_order_choose common.nickname = random_nick() debug('starting sendpayment') class UnsignedTXWallet(common.AbstractWallet): def get_key_from_addr(self, addr): debug('getting privkey of ' + addr) if btc.privtoaddr(auth_privkey, common.get_p2pk_vbyte()) != addr: raise RuntimeError('privkey doesnt match given address') return auth_privkey wallet = UnsignedTXWallet() irc = IRCMessageChannel(common.nickname) taker = CreateUnsignedTx(irc, wallet, auth_utxo, cjamount, destaddr, changeaddr, utxo_data, options, chooseOrdersFunc) try: debug('starting irc') irc.run() except: debug('CRASHING, DUMPING EVERYTHING') debug_dump_object(wallet, ['addr_cache', 'keys', 'wallet_name', 'seed']) debug_dump_object(taker) import traceback debug(traceback.format_exc())
def main(): parser = OptionParser( usage="usage: %prog [options] [wallet file] [destaddr(s)...]", description="Sends bitcoins to many different addresses using coinjoin in" " an attempt to break the link between them. Sending to multiple " " addresses is highly recommended for privacy. This tumbler can" " be configured to ask for more address mid-run, giving the user" " a chance to click `Generate New Deposit Address` on whatever service" " they are using.", ) parser.add_option( "-m", "--mixdepthsource", type="int", dest="mixdepthsrc", help="mixing depth to spend from, default=0", default=0, ) parser.add_option( "-f", "--txfee", type="int", dest="txfee", default=10000, help="miner fee contribution, in satoshis, default=10000", ) parser.add_option( "-x", "--maxcjfee", type="float", dest="maxcjfee", default=0.01, help="maximum coinjoin fee the tumbler is willing to pay to a single market maker. default=0.01 (1%)", ) parser.add_option( "-a", "--addrask", type="int", dest="addrask", default=2, help="How many more addresses to ask for in the terminal. Should " "be similar to --txcountparams. default=2", ) parser.add_option( "-N", "--makercountrange", type="float", nargs=2, action="store", dest="makercountrange", help="Input the mean and spread of number of makers to use. e.g. 3 1.5 will be a normal distribution " "with mean 3 and standard deveation 1.5 inclusive, default=3 1.5", default=(3, 1.5), ) parser.add_option( "-M", "--mixdepthcount", type="int", dest="mixdepthcount", help="How many mixing depths to mix through", default=4, ) parser.add_option( "-c", "--txcountparams", type="float", nargs=2, dest="txcountparams", default=(5, 1), help="The number of transactions to take coins from one mixing depth to the next, it is" " randomly chosen following a normal distribution. Should be similar to --addrask. " "This option controlls the parameters of that normal curve. (mean, standard deviation). default=(3, 1)", ) parser.add_option( "--amountpower", type="float", dest="amountpower", default=100.0, help="The output amounts follow a power law distribution, this is the power, default=100.0", ) parser.add_option( "-l", "--timelambda", type="float", dest="timelambda", default=20, help="Average the number of minutes to wait between transactions. Randomly chosen " " following an exponential distribution, which describes the time between uncorrelated" " events. default=20", ) parser.add_option( "-w", "--wait-time", action="store", type="float", dest="waittime", help="wait time in seconds to allow orders to arrive, default=5", default=5, ) parser.add_option( "-s", "--mincjamount", type="int", dest="mincjamount", default=100000, help="minimum coinjoin amount in transaction in satoshi, default 100k", ) (options, args) = parser.parse_args() # TODO somehow implement a lower limit if len(args) < 1: parser.error("Needs a wallet file") sys.exit(0) wallet_file = args[0] destaddrs = args[1:] common.load_program_config() for addr in destaddrs: addr_valid, errormsg = validate_address(addr) if not addr_valid: print "ERROR: Address " + addr + " invalid. " + errormsg return if len(destaddrs) + options.addrask <= 1: print "=" * 50 print "WARNING: You are only using one destination address" print "this is very bad for privacy" print "=" * 50 print str(options) tx_list = generate_tumbler_tx(destaddrs, options) if not tx_list: return tx_list2 = copy.deepcopy(tx_list) tx_dict = {} for tx in tx_list2: srcmixdepth = tx["srcmixdepth"] tx.pop("srcmixdepth") if srcmixdepth not in tx_dict: tx_dict[srcmixdepth] = [] tx_dict[srcmixdepth].append(tx) dbg_tx_list = [] for srcmixdepth, txlist in tx_dict.iteritems(): dbg_tx_list.append({"srcmixdepth": srcmixdepth, "tx": txlist}) debug("tumbler transaction list") pprint(dbg_tx_list) total_wait = sum([tx["wait"] for tx in tx_list]) print "waits in total for " + str(len(tx_list)) + " blocks and " + str(total_wait) + " minutes" total_block_and_wait = len(tx_list) * 10 + total_wait print ( "estimated time taken " + str(total_block_and_wait) + " minutes or " + str(round(total_block_and_wait / 60.0, 2)) + " hours" ) ret = raw_input("tumble with these tx? (y/n):") if ret[0] != "y": return # NOTE: possibly out of date documentation # a couple of modes # im-running-from-the-nsa, takes about 80 hours, costs a lot # python tumbler.py -a 10 -N 10 5 -c 10 5 -l 50 -M 10 wallet_file 1xxx # # quick and cheap, takes about 90 minutes # python tumbler.py -N 2 1 -c 3 0.001 -l 10 -M 3 -a 1 wallet_file 1xxx # # default, good enough for most, takes about 5 hours # python tumbler.py wallet_file 1xxx # # for quick testing # python tumbler.py -N 2 1 -c 3 0.001 -l 0.1 -M 3 -a 0 wallet_file 1xxx 1yyy wallet = Wallet(wallet_file, max_mix_depth=options.mixdepthsrc + options.mixdepthcount) common.bc_interface.sync_wallet(wallet) common.nickname = random_nick() debug("starting tumbler") irc = IRCMessageChannel(common.nickname) tumbler = Tumbler(irc, wallet, tx_list, options.txfee, options.maxcjfee, options.mincjamount) try: debug("connecting to irc") irc.run() except: debug("CRASHING, DUMPING EVERYTHING") debug_dump_object(wallet, ["addr_cache", "keys", "seed"]) debug_dump_object(tumbler) import traceback debug(traceback.format_exc())