Example #1
0
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()
Example #2
0
def main():
	common.load_program_config()
	import sys
	seed = sys.argv[1]
	if isinstance(common.bc_interface, blockchaininterface.BlockrInterface):
		print '\nYou are running a yield generator by polling the blockr.io website'
		print 'This is quite bad for privacy. That site is owned by coinbase.com'
                print 'Also your bot will run faster and more efficently, you can be immediately notified of new bitcoin network'
		print ' information so your money will be working for you as hard as possible'
		print 'Learn how to setup JoinMarket with Bitcoin Core: https://github.com/chris-belcher/joinmarket/wiki/Running-JoinMarket-with-Bitcoin-Core-full-node'
		ret = raw_input('\nContinue? (y/n):')
		if ret[0] != 'y':
			return

	wallet = Wallet(seed, max_mix_depth = mix_levels)
	common.bc_interface.sync_wallet(wallet)
	
	common.nickname = nickname
	debug('starting yield generator')
	irc = IRCMessageChannel(common.nickname, realname='btcint=' + common.config.get("BLOCKCHAIN", "blockchain_source"),
		password=nickserv_password)
	maker = YieldGenerator(irc, wallet)
	try:
		debug('connecting to irc')
		irc.run()
	except:
		debug('CRASHING, DUMPING EVERYTHING')
		debug_dump_object(wallet, ['addr_cache', 'keys', 'seed'])
		debug_dump_object(maker)
		debug_dump_object(irc)
		import traceback
		debug(traceback.format_exc())
Example #3
0
def main():
    common.load_program_config()
    import sys
    seed = sys.argv[1]
    wallet = Wallet(seed, max_mix_depth=mix_levels)
    common.bc_interface.sync_wallet(wallet)
    wallet.print_debug_wallet_info()

    common.nickname = nickname
    debug('starting yield generator')
    irc = IRCMessageChannel(
        common.nickname,
        realname='btcint=' +
        common.config.get("BLOCKCHAIN", "blockchain_source"),
        password=nickserv_password)
    maker = YieldGenerator(irc, wallet)
    try:
        debug('connecting to irc')
        irc.run()
    except:
        debug('CRASHING, DUMPING EVERYTHING')
        debug_dump_object(wallet, ['addr_cache', 'keys', 'seed'])
        debug_dump_object(maker)
        debug_dump_object(irc)
        import traceback
        debug(traceback.format_exc())
Example #4
0
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()
Example #5
0
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()
Example #6
0
def main():
	from socket import gethostname
	nickname = 'cj-maker-' + btc.sha256(gethostname())[:6]
	import sys
	seed = sys.argv[1] #btc.sha256('dont use brainwallets except for holding testnet coins')

	common.load_program_config()
	wallet = Wallet(seed, max_mix_depth=5)
	common.bc_interface.sync_wallet(wallet)

	from irc import IRCMessageChannel
	irc = IRCMessageChannel(nickname)
	maker = Maker(irc, wallet)
	try:
		print 'connecting to irc'
		irc.run()
	except:
		debug('CRASHING, DUMPING EVERYTHING')
		debug('wallet seed = ' + seed)
		debug_dump_object(wallet, ['addr_cache'])
		debug_dump_object(maker)
		import traceback
		traceback.print_exc()
Example #7
0
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] [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] [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())
Example #10
0
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())
Example #11
0
	+ ' showseed - shows the wallet recovery seed and hex seed.')
parser.add_option('-p', '--privkey', action='store_true', dest='showprivkey',
	help='print private key along with address, default false')
parser.add_option('-m', '--maxmixdepth', action='store', type='int', dest='maxmixdepth',
	default=5, help='maximum mixing depth to look for, default=5')
parser.add_option('-g', '--gap-limit', type="int", action='store', dest='gaplimit',
	help='gap limit for wallet, default=6', default=6)
(options, args) = parser.parse_args()

noseed_methods = ['generate', 'recover']
methods = ['display', 'displayall', 'summary'] + noseed_methods

if len(args) < 1:
	parser.error('Needs a wallet file or method')
	sys.exit(0)
load_program_config()

if args[0] in noseed_methods:
	method = args[0]
else:
	seed = args[0]
	method = ('display' if len(args) == 1 else args[1].lower())
	wallet = Wallet(seed, options.maxmixdepth, options.gaplimit)
	if method != 'showseed':
		common.bc_interface.sync_wallet(wallet)

if method == 'display' or method == 'displayall':
	total_balance = 0
	for m in range(wallet.max_mix_depth):
		print 'mixing depth %d m/0/%d/' % (m, m)
		balance_depth = 0
Example #12
0
def main():
    common.load_program_config()
    if not common.bc_interface:
	print 'not there'
	exit()
    unittest.main()
Example #13
0
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())
Example #14
0
                  help='maximum mixing depth to look for, default=5')
parser.add_option('-g',
                  '--gap-limit',
                  action='store',
                  dest='gaplimit',
                  help='gap limit for wallet, default=6',
                  default=6)
(options, args) = parser.parse_args()

noseed_methods = ['generate', 'recover']
methods = ['display', 'displayall', 'summary'] + noseed_methods

if len(args) < 1:
    parser.error('Needs a wallet file or method')
    sys.exit(0)
load_program_config()

if args[0] in noseed_methods:
    method = args[0]
else:
    seed = args[0]
    method = ('display' if len(args) == 1 else args[1].lower())
    wallet = Wallet(seed, options.maxmixdepth)
    if method != 'showseed':
        common.bc_interface.sync_wallet(wallet, options.gaplimit)

if method == 'display' or method == 'displayall':
    total_balance = 0
    for m in range(wallet.max_mix_depth):
        print 'mixing depth %d m/0/%d/' % (m, m)
        balance_depth = 0
Example #15
0
def main():
    os.chdir(data_dir)
    common.load_program_config()
    unittest.main()
Example #16
0
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())
Example #17
0
            testlog = open('test_recover', 'wb')
            p = pexpect.spawn('python wallet-tool.py recover', logfile=testlog)
            expected = [
                'Input 12 word recovery seed',
                'Enter wallet encryption passphrase:',
                'Reenter wallet encryption passphrase:',
                'Input wallet file name'
            ]
            test_in = [seed, 'abc123', 'abc123', 'test_recover_wallet.json']
            commontest.interact(p, test_in, expected)
            p.expect('saved to')
            p.close()
            testlog.close()
            #anything to check in the log?
            if p.exitstatus != 0:
                print 'failed due to exit status: ' + str(p.exitstatus)
                return False
            #check the wallet exists (and contains appropriate json? todo)
            if not os.path.isfile('wallets/test_recover_wallet.json'):
                print 'failed due to wallet missing'
                return False
            os.remove('wallets/test_recover_wallet.json')
        except:
            return False
        return True


if __name__ == '__main__':
    os.chdir(data_dir)
    common.load_program_config()
    unittest.main()
Example #18
0
def main():
    os.chdir(data_dir)
    common.load_program_config()
    unittest.main()
Example #19
0
    
    def run_recover(self, seed):
	try:
	    testlog = open('test_recover','wb')
	    p = pexpect.spawn('python wallet-tool.py recover', logfile = testlog)
	    expected = ['Input 12 word recovery seed',
		        'Enter wallet encryption passphrase:',
		        'Reenter wallet encryption passphrase:',
		        'Input wallet file name']
	    test_in = [seed, 'abc123', 'abc123', 'test_recover_wallet.json']
	    interact(p, test_in, expected)
	    p.expect('saved to')
	    p.close()
	    testlog.close()
	    #anything to check in the log? 
	    if p.exitstatus != 0:
		print 'failed due to exit status: '+str(p.exitstatus)
		return False
	    #check the wallet exists (and contains appropriate json? todo)
	    if not os.path.isfile('wallets/test_recover_wallet.json'):
		print 'failed due to wallet missing'
		return False
	    os.remove('wallets/test_recover_wallet.json')	
	except:
	    return False
	return True
    
if __name__ == '__main__':
    os.chdir(data_dir)
    common.load_program_config()
    unittest.main()
Example #20
0
def main():
    common.load_program_config()
    if not common.bc_interface:
        print 'not there'
        exit()
    unittest.main()
Example #21
0
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())