def __init__(self, blockr_domain, txd, unconfirmfun, confirmfun):
				threading.Thread.__init__(self)
				self.daemon = True
				self.blockr_domain = blockr_domain
				self.unconfirmfun = unconfirmfun
				self.confirmfun = confirmfun
				self.tx_output_set = set([(sv['script'], sv['value']) for sv in txd['outs']])
				self.output_addresses = [btc.script_to_address(scrval[0],
					common.get_p2pk_vbyte()) for scrval in self.tx_output_set]
				common.debug('txoutset=' + pprint.pformat(self.tx_output_set))
				common.debug('outaddrs=' + ','.join(self.output_addresses))
			def __init__(self, blockr_domain, txd, unconfirmfun, confirmfun):
				threading.Thread.__init__(self)
				self.daemon = True
				self.blockr_domain = blockr_domain
				self.unconfirmfun = unconfirmfun
				self.confirmfun = confirmfun
				self.tx_output_set = set([(sv['script'], sv['value']) for sv in txd['outs']])
				self.output_addresses = [btc.script_to_address(scrval[0],
					common.get_p2pk_vbyte()) for scrval in self.tx_output_set]
				common.debug('txoutset=' + pprint.pformat(self.tx_output_set))
				common.debug('outaddrs=' + ','.join(self.output_addresses))
	def add_tx_notify(self, txd, unconfirmfun, confirmfun, notifyaddr):
		if not self.notifythread:
			self.notifythread = BitcoinCoreNotifyThread(self)
			self.notifythread.start()
		one_addr_imported = False
		for outs in txd['outs']:
			addr = btc.script_to_address(outs['script'], common.get_p2pk_vbyte())
			if self.rpc('getaccount', [addr]) != '':
				one_addr_imported = True
				break
		if not one_addr_imported:
			self.rpc('importaddress', [notifyaddr, 'joinmarket-notify', False])
		tx_output_set = set([(sv['script'], sv['value']) for sv in txd['outs']])
		self.txnotify_fun.append((tx_output_set, unconfirmfun, confirmfun))
	def add_tx_notify(self, txd, unconfirmfun, confirmfun, notifyaddr):
		if not self.notifythread:
			self.notifythread = BitcoinCoreNotifyThread(self)
			self.notifythread.start()
		one_addr_imported = False
		for outs in txd['outs']:
			addr = btc.script_to_address(outs['script'], common.get_p2pk_vbyte())
			if self.rpc('getaccount', [addr]) != '':
				one_addr_imported = True
				break
		if not one_addr_imported:
			self.rpc('importaddress', [notifyaddr, 'joinmarket-notify', False])
		tx_output_set = set([(sv['script'], sv['value']) for sv in txd['outs']])
		self.txnotify_fun.append((tx_output_set, unconfirmfun, confirmfun))
Example #5
0
    def run_simple_send(self, n, m):
        #start yield generator with wallet1
	yigen_proc = local_command(['python','yield-generator.py', 
	                            str(self.wallets[0]['seed'])],bg=True)
	
	#A significant delay is needed to wait for the yield generator to sync its wallet
	time.sleep(30)
	
	#run a single sendpayment call with wallet2
	amt = n*100000000 #in satoshis
	dest_address = btc.privkey_to_address(os.urandom(32), common.get_p2pk_vbyte())
	try:
	    for i in range(m):
		sp_proc = local_command(['python','sendpayment.py','--yes','-N','1', self.wallets[1]['seed'],\
	                                       str(amt), dest_address])
	except subprocess.CalledProcessError, e:
	    if yigen_proc:
		yigen_proc.terminate()
	    print e.returncode
	    print e.message
	    raise
Example #6
0
    def run_nparty_join(self):
	yigen_procs = []
	for i in range(self.n):
	    ygp = local_command(['python','yield-generator.py',\
	                         str(self.wallets[i]['seed'])], bg=True)
	    time.sleep(2) #give it a chance
	    yigen_procs.append(ygp)
	
	#A significant delay is needed to wait for the yield generators to sync 
	time.sleep(60)
	
	#run a single sendpayment call
	amt = 100000000 #in satoshis
	dest_address = btc.privkey_to_address(os.urandom(32), common.get_p2pk_vbyte())
	try:
	    sp_proc = local_command(['python','sendpayment.py','--yes','-N', str(self.n),\
	                             self.wallets[self.n]['seed'], str(amt), dest_address])
	except subprocess.CalledProcessError, e:
	    for ygp in yigen_procs:
		ygp.kill()
	    print e.returncode
	    print e.message
	    raise
Example #7
0
    def run_simple_send(self, n, m):
        #start yield generator with wallet1
        yigen_proc = local_command(
            ['python', 'yield-generator.py',
             str(self.wallets[0]['seed'])],
            bg=True)

        #A significant delay is needed to wait for the yield generator to sync its wallet
        time.sleep(30)

        #run a single sendpayment call with wallet2
        amt = n * 100000000  #in satoshis
        dest_address = btc.privkey_to_address(os.urandom(32),
                                              common.get_p2pk_vbyte())
        try:
            for i in range(m):
                sp_proc = local_command(['python','sendpayment.py','--yes','-N','1', self.wallets[1]['seed'],\
                                                      str(amt), dest_address])
        except subprocess.CalledProcessError, e:
            if yigen_proc:
                yigen_proc.terminate()
            print e.returncode
            print e.message
            raise
Example #8
0
    def run_nparty_join(self):
        yigen_procs = []
        for i in range(self.n):
            ygp = local_command(['python','yield-generator.py',\
                                 str(self.wallets[i]['seed'])], bg=True)
            time.sleep(2)  #give it a chance
            yigen_procs.append(ygp)

        #A significant delay is needed to wait for the yield generators to sync
        time.sleep(60)

        #run a single sendpayment call
        amt = 100000000  #in satoshis
        dest_address = btc.privkey_to_address(os.urandom(32),
                                              common.get_p2pk_vbyte())
        try:
            sp_proc = local_command(['python','sendpayment.py','--yes','-N', str(self.n),\
                                     self.wallets[self.n]['seed'], str(amt), dest_address])
        except subprocess.CalledProcessError, e:
            for ygp in yigen_procs:
                ygp.kill()
            print e.returncode
            print e.message
            raise
Example #9
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 #10
0
	for m in range(wallet.max_mix_depth):
		printd('mixing depth %d m/0/%d/' % (m, m))
		balance_depth = 0
		for forchange in [0, 1]:
			printd(' ' + ('receive' if forchange==0 else 'change') +
				' addresses m/0/%d/%d/' % (m, forchange))
			for k in range(wallet.index[m][forchange] + options.gaplimit):
				addr = wallet.get_addr(m, forchange, k)
				balance = 0.0
				for addrvalue in wallet.unspent.values():
					if addr == addrvalue['address']:
						balance += addrvalue['value']
				balance_depth += balance
				used = ('used' if k < wallet.index[m][forchange] else ' new')
				privkey = btc.encode_privkey(wallet.get_key(m, forchange, k), 'wif_compressed',
					get_p2pk_vbyte()) if options.showprivkey else ''
				if method == 'displayall' or  balance > 0 or (used == ' new' and forchange==0):
					printd('  m/0/%d/%d/%03d %-35s%s %.8f btc %s' % (m, forchange, k, addr, used, balance/1e8, privkey))
		if m in wallet.imported_privkeys:
			printd(' import addresses')
			for privkey in wallet.imported_privkeys[m]:
				addr = btc.privtoaddr(privkey, common.get_p2pk_vbyte())
				balance = 0.0
				for addrvalue in wallet.unspent.values():
					if addr == addrvalue['address']:
						balance += addrvalue['value']
				used = (' used' if balance > 0.0 else 'empty')
				balance_depth += balance
				wip_privkey = btc.encode_privkey(privkey, 'wif_compressed',
					get_addr_vbyte()) if options.showprivkey else ''
				printd(' '*13 + '%-35s%s %.8f btc %s' % (addr, used, balance/1e8, wip_privkey))
Example #11
0
 printd('mixing depth %d m/0/%d/' % (m, m))
 balance_depth = 0
 for forchange in [0, 1]:
     printd(' ' + ('receive' if forchange == 0 else 'change') +
            ' addresses m/0/%d/%d/' % (m, forchange))
     for k in range(wallet.index[m][forchange] + options.gaplimit):
         addr = wallet.get_addr(m, forchange, k)
         balance = 0.0
         for addrvalue in wallet.unspent.values():
             if addr == addrvalue['address']:
                 balance += addrvalue['value']
         balance_depth += balance
         used = ('used' if k < wallet.index[m][forchange] else ' new')
         privkey = btc.encode_privkey(
             wallet.get_key(m, forchange, k), 'wif_compressed',
             get_p2pk_vbyte()) if options.showprivkey else ''
         if method == 'displayall' or balance > 0 or (used == ' new' and
                                                      forchange == 0):
             printd(
                 '  m/0/%d/%d/%03d %-35s%s %.8f btc %s' %
                 (m, forchange, k, addr, used, balance / 1e8, privkey))
 if m in wallet.imported_privkeys:
     printd(' import addresses')
     for privkey in wallet.imported_privkeys[m]:
         addr = btc.privtoaddr(privkey, common.get_p2pk_vbyte())
         balance = 0.0
         for addrvalue in wallet.unspent.values():
             if addr == addrvalue['address']:
                 balance += addrvalue['value']
         used = (' used' if balance > 0.0 else 'empty')
         balance_depth += balance
Example #12
0
        print 'mixing depth %d m/0/%d/' % (m, m)
        balance_depth = 0
        for forchange in [0, 1]:
            print(' ' + ('receive' if forchange == 0 else 'change') +
                  ' addresses m/0/%d/%d/' % (m, forchange))
            for k in range(wallet.index[m][forchange] + options.gaplimit):
                addr = wallet.get_addr(m, forchange, k)
                balance = 0.0
                for addrvalue in wallet.unspent.values():
                    if addr == addrvalue['address']:
                        balance += addrvalue['value']
                balance_depth += balance
                used = ('used' if k < wallet.index[m][forchange] else ' new')
                privkey = btc.encode_privkey(
                    wallet.get_key(m, forchange, k), 'wif_compressed',
                    get_p2pk_vbyte()) if options.showprivkey else ''
                if method == 'displayall' or balance > 0 or (used == ' new' and
                                                             forchange == 0):
                    print '  m/0/%d/%d/%03d %-35s%s %.8f btc %s' % (
                        m, forchange, k, addr, used, balance / 1e8, privkey)
        print 'for mixdepth=%d balance=%.8fbtc' % (m, balance_depth / 1e8)
        total_balance += balance_depth
    print 'total balance = %.8fbtc' % (total_balance / 1e8)
elif method == 'summary':
    total_balance = 0
    for m in range(wallet.max_mix_depth):
        balance_depth = 0
        for forchange in [0, 1]:
            for k in range(wallet.index[m][forchange]):
                addr = wallet.get_addr(m, forchange, k)
                for addrvalue in wallet.unspent.values():
Example #13
0
		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
Example #14
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='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 #15
0
 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
    def sync_addresses(self, wallet):
        if isinstance(wallet, common.BitcoinCoreWallet):
            return
        common.debug('requesting wallet history')
        wallet_name = self.get_wallet_name(wallet)
        addr_req_count = 20
        wallet_addr_list = []
        for mix_depth in range(wallet.max_mix_depth):
            for forchange in [0, 1]:
                wallet_addr_list += [
                    wallet.get_new_addr(mix_depth, forchange)
                    for i in range(addr_req_count)
                ]
                wallet.index[mix_depth][forchange] = 0
        #makes more sense to add these in an account called "joinmarket-imported" but its much
        # simpler to add to the same account here
        for privkey_list in wallet.imported_privkeys.values():
            for privkey in privkey_list:
                imported_addr = btc.privtoaddr(privkey,
                                               common.get_p2pk_vbyte())
                wallet_addr_list.append(imported_addr)
        imported_addr_list = self.rpc('getaddressesbyaccount', [wallet_name])
        if not set(wallet_addr_list).issubset(set(imported_addr_list)):
            self.add_watchonly_addresses(wallet_addr_list, wallet_name)
            return

        buf = self.rpc('listtransactions', [wallet_name, 1000, 0, True])
        txs = buf
        # If the buffer's full, check for more, until it ain't
        while len(buf) == 1000:
            buf = self.rpc(
                'listtransactions',
                [wallet_name, 1000, len(txs), True])
            txs += buf
        #TODO check whether used_addr_list can be a set, may be faster (if its a hashset) and allows
        # using issubset() here and setdiff() for finding which addresses need importing
        #TODO also check the fastest way to build up python lists, i suspect using += is slow
        used_addr_list = [
            tx['address'] for tx in txs if tx['category'] == 'receive'
        ]
        too_few_addr_mix_change = []
        for mix_depth in range(wallet.max_mix_depth):
            for forchange in [0, 1]:
                unused_addr_count = 0
                last_used_addr = ''
                breakloop = False
                while not breakloop:
                    if unused_addr_count >= wallet.gaplimit and\
                      is_index_ahead_of_cache(wallet, mix_depth, forchange):
                        break
                    mix_change_addrs = [
                        wallet.get_new_addr(mix_depth, forchange)
                        for i in range(addr_req_count)
                    ]
                    for mc_addr in mix_change_addrs:
                        if mc_addr not in imported_addr_list:
                            too_few_addr_mix_change.append(
                                (mix_depth, forchange))
                            breakloop = True
                            break
                        if mc_addr in used_addr_list:
                            last_used_addr = mc_addr
                            unused_addr_count = 0
                        else:
                            unused_addr_count += 1

                if last_used_addr == '':
                    wallet.index[mix_depth][forchange] = 0
                else:
                    wallet.index[mix_depth][
                        forchange] = wallet.addr_cache[last_used_addr][2] + 1

        wallet_addr_list = []
        if len(too_few_addr_mix_change) > 0:
            common.debug('too few addresses in ' +
                         str(too_few_addr_mix_change))
            for mix_depth, forchange in too_few_addr_mix_change:
                wallet_addr_list += [
                    wallet.get_new_addr(mix_depth, forchange)
                    for i in range(addr_req_count * 3)
                ]
            self.add_watchonly_addresses(wallet_addr_list, wallet_name)
            return

        self.wallet_synced = True
	def sync_addresses(self, wallet):
		if isinstance(wallet, common.BitcoinCoreWallet):
			return
		common.debug('requesting wallet history')
		wallet_name = self.get_wallet_name(wallet)
		addr_req_count = 20
		wallet_addr_list = []
		for mix_depth in range(wallet.max_mix_depth):
			for forchange in [0, 1]:
				wallet_addr_list += [wallet.get_new_addr(mix_depth, forchange) for i in range(addr_req_count)]
				wallet.index[mix_depth][forchange] = 0
		#makes more sense to add these in an account called "joinmarket-imported" but its much
		# simpler to add to the same account here
		for privkey_list in wallet.imported_privkeys.values():
			for privkey in privkey_list:
				imported_addr = btc.privtoaddr(privkey, common.get_p2pk_vbyte())
				wallet_addr_list.append(imported_addr)
		imported_addr_list = self.rpc('getaddressesbyaccount', [wallet_name])
		if not set(wallet_addr_list).issubset(set(imported_addr_list)):
			self.add_watchonly_addresses(wallet_addr_list, wallet_name)
			return

		buf = self.rpc('listtransactions', [wallet_name, 1000, 0, True])
		txs = buf
		# If the buffer's full, check for more, until it ain't
		while len(buf) == 1000:
			buf = self.rpc('listtransactions', [wallet_name, 1000,
					len(txs), True])
			txs += buf
		#TODO check whether used_addr_list can be a set, may be faster (if its a hashset) and allows 
		# using issubset() here and setdiff() for finding which addresses need importing
		#TODO also check the fastest way to build up python lists, i suspect using += is slow
		used_addr_list = [tx['address'] for tx in txs if tx['category'] == 'receive']
		too_few_addr_mix_change = []
		for mix_depth in range(wallet.max_mix_depth):
			for forchange in [0, 1]:
				unused_addr_count = 0
				last_used_addr = ''
				breakloop = False
				while not breakloop:
					if unused_addr_count >= wallet.gaplimit and\
							wallet.index[mix_depth][forchange] >= wallet.index_cache[mix_depth][forchange]:
						break
					mix_change_addrs = [wallet.get_new_addr(mix_depth, forchange) for i in range(addr_req_count)]
					for mc_addr in mix_change_addrs:
						if mc_addr not in imported_addr_list:
							too_few_addr_mix_change.append((mix_depth, forchange))
							breakloop = True
							break
						if mc_addr in used_addr_list:
							last_used_addr = mc_addr
							unused_addr_count = 0
						else:
							unused_addr_count += 1

				if last_used_addr == '':
					wallet.index[mix_depth][forchange] = 0
				else:
					wallet.index[mix_depth][forchange] = wallet.addr_cache[last_used_addr][2] + 1

		wallet_addr_list = []
		if len(too_few_addr_mix_change) > 0:
			common.debug('too few addresses in ' + str(too_few_addr_mix_change))
			for mix_depth, forchange in too_few_addr_mix_change:
				wallet_addr_list += [wallet.get_new_addr(mix_depth, forchange) for i in range(addr_req_count*3)]
			self.add_watchonly_addresses(wallet_addr_list, wallet_name)
			return

		self.wallet_synced = True