diff --git a/joinmarket/maker.py b/joinmarket/maker.py index e42cf6f5..5accf60a 100644 --- a/joinmarket/maker.py +++ b/joinmarket/maker.py @@ -234,7 +234,8 @@ def verify_unsigned_tx(self, txd): if outs['value'] != expected_change_value: return False, 'wrong change, i expect ' + str( expected_change_value) - if times_seen_cj_addr != 1 or times_seen_change_addr != 1: + if (times_seen_cj_addr != 1 or # allow "sweeping" empty change + (expected_change_value != 0 and times_seen_change_addr != 1)): fmt = ('cj or change addr not in tx ' 'outputs once, #cjaddr={}, #chaddr={}').format return False, (fmt(times_seen_cj_addr, times_seen_change_addr)) diff --git a/joinmarket/taker.py b/joinmarket/taker.py index 59b50238..ee4102f0 100644 --- a/joinmarket/taker.py +++ b/joinmarket/taker.py @@ -179,18 +179,16 @@ def recv_txio(self, nick, utxo_list, auth_pub, cj_addr, change_addr): change_amount = (total_input - self.cj_amount - self.active_orders[nick]['txfee'] + real_cjfee) - # certain malicious and/or incompetent liquidity providers send - # inputs totalling less than the coinjoin amount! this leads to - # a change output of zero satoshis, so the invalid transaction - # fails harmlessly; let's fail earlier, with a clear message. - if change_amount < jm_single().BITCOIN_DUST_THRESHOLD: - fmt = ('ERROR counterparty requires sub-dust change. No ' - 'action required. nick={}' + # change must either be above the DUST_THRESHOLD, or exactly zero + if change_amount != 0 and change_amount < jm_single().DUST_THRESHOLD: + fmt = ('ERROR counterparty requires sub-dust change. nick={}' 'totalin={:d} cjamount={:d} change={:d}').format - log.warn(fmt(nick, total_input, self.cj_amount, change_amount)) + log.debug(fmt(nick, total_input, self.cj_amount, change_amount)) return # timeout marks this maker as nonresponsive - self.outputs.append({'address': change_addr, 'value': change_amount}) + if change_amount != 0: # FIXME add support for this from maker-side + self.outputs.append({'address': change_addr, 'value': change_amount}) + fmt = ('fee breakdown for {} totalin={:d} ' 'cjamount={:d} txfee={:d} realcjfee={:d}').format log.debug(fmt(nick, total_input, self.cj_amount, @@ -209,6 +207,28 @@ def recv_txio(self, nick, utxo_list, auth_pub, cj_addr, change_addr): assert len(self.active_orders.keys()) >= jm_single().config.getint( "POLICY", "minimum_makers") log.info('got all parts, enough to build a tx') +======= + total_input = sum([d['value'] for d in utxo_data]) + real_cjfee = calc_cj_fee(self.active_orders[nick]['ordertype'], + self.active_orders[nick]['cjfee'], self.cj_amount) + change_amount = (total_input - self.cj_amount - + self.active_orders[nick]['txfee'] + real_cjfee) + + + fmt = ('fee breakdown for {} totalin={:d} ' + 'cjamount={:d} txfee={:d} realcjfee={:d}').format + log.debug(fmt(nick, total_input, self.cj_amount, + self.active_orders[nick]['txfee'], real_cjfee)) + cj_addr = btc.pubtoaddr(cj_pub, get_p2pk_vbyte()) + self.outputs.append({'address': cj_addr, 'value': self.cj_amount}) + self.cjfee_total += real_cjfee + self.maker_txfee_contributions += self.active_orders[nick]['txfee'] + self.nonrespondants.remove(nick) + if len(self.nonrespondants) > 0: + log.debug('nonrespondants = ' + str(self.nonrespondants)) + return + log.debug('got all parts, enough to build a tx') +>>>>>>> skip empty change addresses for makers self.nonrespondants = list(self.active_orders.keys()) my_total_in = sum([va['value'] for u, va in