def auth_counterparty(self, nick, cr): #deserialize the commitment revelation cr_dict = btc.PoDLE.deserialize_revelation(cr) #check the validity of the proof of discrete log equivalence tries = jm_single().config.getint("POLICY", "taker_utxo_retries") def reject(msg): log.info("Counterparty commitment not accepted, reason: " + msg) return False if not btc.verify_podle(cr_dict['P'], cr_dict['P2'], cr_dict['sig'], cr_dict['e'], self.maker.commit, index_range=range(tries)): reason = "verify_podle failed" return reject(reason) #finally, check that the proffered utxo is real, old enough, large enough, #and corresponds to the pubkey res = jm_single().bc_interface.query_utxo_set([cr_dict['utxo']], includeconf=True) if len(res) != 1 or not res[0]: reason = "authorizing utxo is not valid" return reject(reason) age = jm_single().config.getint("POLICY", "taker_utxo_age") if res[0]['confirms'] < age: reason = "commitment utxo not old enough: " + str(res[0]['confirms']) return reject(reason) reqd_amt = int(self.cj_amount * jm_single().config.getint( "POLICY", "taker_utxo_amtpercent") / 100.0) if res[0]['value'] < reqd_amt: reason = "commitment utxo too small: " + str(res[0]['value']) return reject(reason) if res[0]['address'] != btc.pubkey_to_address(cr_dict['P'], get_p2pk_vbyte()): reason = "Invalid podle pubkey: " + str(cr_dict['P']) return reject(reason) # authorisation of taker passed # Send auth request to taker # Need to choose an input utxo pubkey to sign with # (no longer using the coinjoin pubkey from 0.2.0) # Just choose the first utxo in self.utxos and retrieve key from wallet. auth_address = self.utxos[self.utxos.keys()[0]]['address'] auth_key = self.maker.wallet.get_key_from_addr(auth_address) auth_pub = btc.privtopub(auth_key) btc_sig = btc.ecdsa_sign(self.kp.hex_pk(), auth_key) self.maker.msgchan.send_ioauth(nick, self.utxos.keys(), auth_pub, self.cj_addr, self.change_addr, btc_sig) #In case of *blacklisted (ie already used) commitments, we already #broadcasted them on receipt; in case of valid, and now used commitments, #we broadcast them here, and not early - to avoid accidentally #blacklisting commitments that are broadcast between makers in real time #for the same transaction. self.maker.transfer_commitment(self.maker.commit) #now persist the fact that the commitment is actually used. check_utxo_blacklist(self.maker.commit, persist=True) return True
def on_order_fill(self, nick, oid, amount, taker_pubkey, commit): if nick in self.active_orders and self.active_orders[nick] is not None: self.active_orders[nick] = None log.info('had a partially filled order but starting over now') if not commit[0] == "P": self.msgchan.send_error( nick, "Unsupported commitment type: " + str(commit[0])) return #Strip the type byte before processing scommit = commit[1:] if not check_utxo_blacklist(scommit): log.info("Taker utxo commitment is blacklisted, rejecting.") self.msgchan.send_error(nick, "Commitment is blacklisted: " + str(scommit)) #Note that broadcast is happening here to reflect an already #consumed commitment; it can also be broadcast separately (earlier) on #valid usage in CoinjoinOrder.auth_counterparty(). #Keep the type byte for communication so not scommit: self.transfer_commitment(commit) return self.commit = scommit self.wallet_unspent_lock.acquire() try: self.active_orders[nick] = CoinJoinOrder(self, nick, oid, amount, taker_pubkey) finally: self.wallet_unspent_lock.release()
def on_order_fill(self, nick, oid, amount, taker_pubkey, commit): if nick in self.active_orders and self.active_orders[nick] is not None: self.active_orders[nick] = None log.debug('had a partially filled order but starting over now') if not commit[0] == "P": self.msgchan.send_error( nick, "Unsupported commitment type: " + str(commit[0])) return #Strip the type byte before processing scommit = commit[1:] if not check_utxo_blacklist(scommit): log.debug("Taker utxo commitment is blacklisted, rejecting.") self.msgchan.send_error( nick, "Commitment is blacklisted: " + str(scommit)) #Note that broadcast is happening here to reflect an already #consumed commitment; it can also be broadcast separately (earlier) on #valid usage in CoinjoinOrder.auth_counterparty(). #Keep the type byte for communication so not scommit: self.transfer_commitment(commit) return self.commit = scommit self.wallet_unspent_lock.acquire() try: self.active_orders[nick] = CoinJoinOrder(self, nick, oid, amount, taker_pubkey) finally: self.wallet_unspent_lock.release()
def on_commitment_seen(self, nick, commitment): """Triggered when we see a commitment for blacklisting appear in the public pit channel. If the policy is set, we blacklist this commitment. """ if jm_single().config.has_option("POLICY", "accept_commitment_broadcasts"): blacklist_add = jm_single().config.getint("POLICY", "accept_commitment_broadcasts") else: blacklist_add = 0 if blacklist_add > 0: #just add if necessary, ignore return value. check_utxo_blacklist(commitment, persist=True) log.debug("Received commitment broadcast by other maker: " + str( commitment) + ", now blacklisted.") else: log.debug("Received commitment broadcast by other maker: " + str( commitment) + ", ignored.")
def on_commitment_seen(self, nick, commitment): """Triggered when we see a commitment for blacklisting appear in the public pit channel. If the policy is set, we blacklist this commitment. """ if jm_single().config.has_option("POLICY", "accept_commitment_broadcasts"): blacklist_add = jm_single().config.getint( "POLICY", "accept_commitment_broadcasts") else: blacklist_add = 0 if blacklist_add > 0: #just add if necessary, ignore return value. check_utxo_blacklist(commitment, persist=True) log.debug("Received commitment broadcast by other maker: " + str(commitment) + ", now blacklisted.") else: log.debug("Received commitment broadcast by other maker: " + str(commitment) + ", ignored.")
def auth_counterparty(self, nick, cr): #deserialize the commitment revelation cr_dict = btc.PoDLE.deserialize_revelation(cr) #check the validity of the proof of discrete log equivalence tries = jm_single().config.getint("POLICY", "taker_utxo_retries") def reject(msg): log.debug("Counterparty commitment not accepted, reason: " + msg) return False if not btc.verify_podle(cr_dict['P'], cr_dict['P2'], cr_dict['sig'], cr_dict['e'], self.maker.commit, index_range=range(tries)): reason = "verify_podle failed" return reject(reason) #finally, check that the proffered utxo is real, old enough, large enough, #and corresponds to the pubkey res = jm_single().bc_interface.query_utxo_set([cr_dict['utxo']], includeconf=True) if len(res) != 1 or not res[0]: reason = "authorizing utxo is not valid" return reject(reason) age = jm_single().config.getint("POLICY", "taker_utxo_age") if res[0]['confirms'] < age: reason = "commitment utxo not old enough: " + str( res[0]['confirms']) return reject(reason) reqd_amt = int( self.cj_amount * jm_single().config.getint("POLICY", "taker_utxo_amtpercent") / 100.0) if res[0]['value'] < reqd_amt: reason = "commitment utxo too small: " + str(res[0]['value']) return reject(reason) if res[0]['address'] != btc.pubkey_to_address(cr_dict['P'], get_p2pk_vbyte()): reason = "Invalid podle pubkey: " + str(cr_dict['P']) return reject(reason) # authorisation of taker passed # Send auth request to taker # Need to choose an input utxo pubkey to sign with # (no longer using the coinjoin pubkey from 0.2.0) # Just choose the first utxo in self.utxos and retrieve key from wallet. auth_address = self.utxos[self.utxos.keys()[0]]['address'] auth_key = self.maker.wallet.get_key_from_addr(auth_address) auth_pub = btc.privtopub(auth_key) btc_sig = btc.ecdsa_sign(self.kp.hex_pk(), auth_key) self.maker.msgchan.send_ioauth(nick, self.utxos.keys(), auth_pub, self.cj_addr, self.change_addr, btc_sig) #In case of *blacklisted (ie already used) commitments, we already #broadcasted them on receipt; in case of valid, and now used commitments, #we broadcast them here, and not early - to avoid accidentally #blacklisting commitments that are broadcast between makers in real time #for the same transaction. self.maker.transfer_commitment(self.maker.commit) #now persist the fact that the commitment is actually used. check_utxo_blacklist(self.maker.commit, persist=True) return True