def __init__(self, msgchan, wallet, db, cj_amount, orders, input_utxos, my_cj_addr, my_change_addr, total_txfee, finishcallback, choose_orders_recover, commitment_creator ): """ if my_change is None then there wont be a change address thats used if you want to entirely coinjoin one utxo with no change left over orders is the orders you want to fill {'counterpartynick': order1, 'cp2': order2} each order object is a dict of properties {'oid': 0, 'maxsize': 2000000, 'minsize': 5000, 'cjfee': 10000, 'txfee': 5000} """ log.info( 'starting cj to ' + str(my_cj_addr) + ' with change at ' + str( my_change_addr)) # parameters self.msgchan = msgchan self.wallet = wallet self.db = db self.cj_amount = cj_amount self.active_orders = dict(orders) self.input_utxos = input_utxos self.finishcallback = finishcallback self.total_txfee = total_txfee self.my_cj_addr = my_cj_addr self.my_change_addr = my_change_addr self.choose_orders_recover = choose_orders_recover self.commitment_creator = commitment_creator self.timeout_lock = threading.Condition() # used to wait() and notify() # used to restrict access to certain variables across threads self.timeout_thread_lock = threading.Condition() self.end_timeout_thread = False self.maker_timeout_sec = jm_single().maker_timeout_sec CoinJoinTX.TimeoutThread(self).start() # state variables self.txid = None self.cjfee_total = 0 self.maker_txfee_contributions = 0 self.nonrespondants = list(self.active_orders.keys()) self.all_responded = False self.latest_tx = None # None means they belong to me self.utxos = {None: self.input_utxos.keys()} self.outputs = [] # create DH keypair on the fly for this Tx object self.kp = init_keypair() self.crypto_boxes = {} if not self.get_commitment(input_utxos, self.cj_amount): return self.msgchan.fill_orders(self.active_orders, self.cj_amount, self.kp.hex_pk(), self.commitment)
def __init__(self, msgchan, wallet, db, cj_amount, orders, input_utxos, my_cj_addr, my_change_addr, total_txfee, finishcallback, choose_orders_recover, auth_addr=None): """ if my_change is None then there wont be a change address thats used if you want to entirely coinjoin one utxo with no change left over orders is the orders you want to fill {'counterpartynick': order1, 'cp2': order2} each order object is a dict of properties {'oid': 0, 'maxsize': 2000000, 'minsize': 5000, 'cjfee': 10000, 'txfee': 5000} """ log.debug('starting cj to ' + str(my_cj_addr) + ' with change at ' + str(my_change_addr)) # parameters self.msgchan = msgchan self.wallet = wallet self.db = db self.cj_amount = cj_amount self.active_orders = dict(orders) self.input_utxos = input_utxos self.finishcallback = finishcallback self.total_txfee = total_txfee self.my_cj_addr = my_cj_addr self.my_change_addr = my_change_addr self.choose_orders_recover = choose_orders_recover self.auth_addr = auth_addr self.timeout_lock = threading.Condition( ) # used to wait() and notify() # used to restrict access to certain variables across threads self.timeout_thread_lock = threading.Condition() self.end_timeout_thread = False self.maker_timeout_sec = jm_single().maker_timeout_sec CoinJoinTX.TimeoutThread(self).start() # state variables self.txid = None self.cjfee_total = 0 self.maker_txfee_contributions = 0 self.nonrespondants = list(self.active_orders.keys()) self.all_responded = False self.latest_tx = None # None means they belong to me self.utxos = {None: self.input_utxos.keys()} self.outputs = [] # create DH keypair on the fly for this Tx object self.kp = init_keypair() self.crypto_boxes = {} self.msgchan.fill_orders(self.active_orders, self.cj_amount, self.kp.hex_pk())
def __init__(self, maker, nick, oid, amount, taker_pk): self.tx = None self.i_utxo_pubkey = None self.maker = maker self.oid = oid self.cj_amount = amount if self.cj_amount <= jm_single().DUST_THRESHOLD: self.maker.msgchan.send_error(nick, 'amount below dust threshold') # the btc pubkey of the utxo that the taker plans to use as input self.taker_pk = taker_pk # create DH keypair on the fly for this Order object self.kp = init_keypair() # the encryption channel crypto box for this Order object self.crypto_box = as_init_encryption(self.kp, init_pubkey(taker_pk)) order_s = [o for o in maker.orderlist if o['oid'] == oid] if len(order_s) == 0: self.maker.msgchan.send_error(nick, 'oid not found') order = order_s[0] if amount < order['minsize'] or amount > order['maxsize']: self.maker.msgchan.send_error(nick, 'amount out of range') self.ordertype = order['ordertype'] self.txfee = order['txfee'] self.cjfee = order['cjfee'] log.debug('new cjorder nick=%s oid=%d amount=%d' % (nick, oid, amount)) self.utxos, self.cj_addr, self.change_addr = maker.oid_to_order( self, oid, amount) self.maker.wallet.update_cache_index() if not self.utxos: self.maker.msgchan.send_error( nick, 'unable to fill order constrained by dust avoidance') # TODO make up orders offers in a way that this error cant appear # check nothing has messed up with the wallet code, remove this # code after a while import pprint log.debug('maker utxos = ' + pprint.pformat(self.utxos)) utxo_list = self.utxos.keys() utxo_data = jm_single().bc_interface.query_utxo_set(utxo_list) if None in utxo_data: log.debug('wrongly using an already spent utxo. utxo_data = ' + pprint.pformat(utxo_data)) sys.exit(0) for utxo, data in zip(utxo_list, utxo_data): if self.utxos[utxo]['value'] != data['value']: fmt = 'wrongly labeled utxo, expected value: {} got {}'.format log.debug(fmt(self.utxos[utxo]['value'], data['value'])) sys.exit(0) # always a new address even if the order ends up never being # furfilled, you dont want someone pretending to fill all your # orders to find out which addresses you use self.maker.msgchan.send_pubkey(nick, self.kp.hex_pk())
def __init__(self, maker, nick, oid, amount, taker_pk): self.tx = None self.i_utxo_pubkey = None self.maker = maker self.oid = oid self.cj_amount = amount if self.cj_amount <= jm_single().BITCOIN_DUST_THRESHOLD: self.maker.msgchan.send_error(nick, 'amount below dust threshold') # the btc pubkey of the utxo that the taker plans to use as input self.taker_pk = taker_pk # create DH keypair on the fly for this Order object self.kp = init_keypair() # the encryption channel crypto box for this Order object. # Invalid pubkeys must be handled by giving up gracefully (otherwise DOS) try: self.crypto_box = as_init_encryption(self.kp, init_pubkey(taker_pk)) except NaclError as e: log.info("Unable to setup crypto box with counterparty: " + repr(e)) self.maker.msgchan.send_error(nick, "invalid nacl pubkey: " + taker_pk) return order_s = [o for o in maker.orderlist if o['oid'] == oid] if len(order_s) == 0: self.maker.msgchan.send_error(nick, 'oid not found') order = order_s[0] if amount < order['minsize'] or amount > order['maxsize']: self.maker.msgchan.send_error(nick, 'amount out of range') self.ordertype = order['ordertype'] self.txfee = order['txfee'] self.cjfee = order['cjfee'] log.info('new cjorder nick=%s oid=%d amount=%d' % (nick, oid, amount)) def populate_utxo_data(): self.utxos, self.cj_addr, self.change_addr = maker.oid_to_order( self, oid, amount) self.maker.wallet.update_cache_index() if not self.utxos: self.maker.msgchan.send_error( nick, 'unable to fill order constrained by dust avoidance') # TODO make up orders offers in a way that this error cant appear # check nothing has messed up with the wallet code, remove this # code after a while log.debug('maker utxos = ' + pprint.pformat(self.utxos)) utxos = self.utxos.keys() return (utxos, jm_single().bc_interface.query_utxo_set(utxos)) for i in xrange(10): ##only loop 10 times, not an infinite amount utxo_list, utxo_data = populate_utxo_data() if None not in utxo_data: break log.debug('wrongly selected stale utxos! utxo_data = ' + pprint.pformat(utxo_data)) with self.maker.wallet_unspent_lock: jm_single().bc_interface.sync_unspent(self.maker.wallet) if None in utxo_data: log.error('unable to select non-stale utxo, weird error! quitting') sys.exit(0) for utxo, data in zip(utxo_list, utxo_data): if self.utxos[utxo]['value'] != data['value']: fmt = 'wrongly labeled utxo, expected value: {} got {}'.format log.debug(fmt(self.utxos[utxo]['value'], data['value'])) sys.exit(0) # always a new address even if the order ends up never being # furfilled, you dont want someone pretending to fill all your # orders to find out which addresses you use self.maker.msgchan.send_pubkey(nick, self.kp.hex_pk())