diff --git a/joinmarket/configure.py b/joinmarket/configure.py index 1d35af0c..273141d9 100644 --- a/joinmarket/configure.py +++ b/joinmarket/configure.py @@ -60,6 +60,7 @@ def __getitem__(self, key): global_singleton.ordername_list = ['absoffer', 'reloffer'] global_singleton.commitment_broadcast_list = ['hp2'] global_singleton.maker_timeout_sec = 60 +global_singleton.max_maker_offers_allowed = 5 global_singleton.debug_file_lock = threading.Lock() global_singleton.debug_file_handle = None global_singleton.blacklist_file_lock = threading.Lock() @@ -131,6 +132,11 @@ def jm_single(): # responsive. Should be an integer >=2 for privacy, or set to 0 if you # want to disallow any reduction from your chosen number of makers. minimum_makers = 2 +# For takers: to filter out potentially malicious makers, this is +# the maximum number of offers a maker is allowed to have. If a +# makers has more offers, then he will be disregarded as potential +# counterparty for coinjoins +max_maker_offers_allowed = 5 # the fee estimate is based on a projection of how many satoshis # per kB are needed to get in one of the next N blocks, N set here # as the value of 'tx_fees'. This estimate is high if you set N=2, @@ -348,6 +354,13 @@ def load_program_config(): log.info('TIMEOUT/maker_timeout_sec not found in .cfg file, ' 'using default value') + try: + global_singleton.max_maker_offers_allowed = global_singleton.config.getint( + 'POLICY', 'max_maker_offers_allowed') + except NoOptionError: + log.info('POLICY/max_maker_offers_allowed not found in .cfg file, ' + 'using default value') + # configure the interface to the blockchain on startup global_singleton.bc_interface = get_blockchain_interface_instance( global_singleton.config) diff --git a/joinmarket/support.py b/joinmarket/support.py index 5c991ad7..7b051b32 100644 --- a/joinmarket/support.py +++ b/joinmarket/support.py @@ -381,6 +381,17 @@ def calc_zero_change_cj_amount(ordercombo): return result, cj_amount, total_fee +def remove_makers_with_too_many_offers(db, number_allowed_offers): + # removes makers with more than the number of allowed offers + crows = db.execute( + 'SELECT DISTINCT counterparty FROM orderbook WHERE oid >= ?;', (int(number_allowed_offers),)).fetchall() + + for row in crows: + nick = row["counterparty"] + db.execute('DELETE FROM orderbook WHERE counterparty=?;', (nick,)) + log.debug('The following maker had too many offers and was removed: ' + nick) + + def debug_dump_object(obj, skip_fields=None): if skip_fields is None: skip_fields = [] diff --git a/patientsendpayment.py b/patientsendpayment.py index 68df4453..e636cb84 100644 --- a/patientsendpayment.py +++ b/patientsendpayment.py @@ -11,6 +11,7 @@ from joinmarket import validate_address, jm_single, get_p2pk_vbyte from joinmarket import get_log, choose_orders, weighted_order_choose, \ debug_dump_object, sync_wallet +from joinmarket.support import remove_makers_with_too_many_offers from joinmarket import Wallet import bitcoin as btc @@ -46,6 +47,11 @@ def __init__(self, tmaker): self.ignored_makers = [] def create_tx(self): + log.info('Removing makers with more than ' + + str(jm_single().config.getint("POLICY", "max_maker_offers_allowed")) + + ' offers as configured in joinmarket.cfg') + remove_makers_with_too_many_offers(self.tmaker.db, + jm_single().config.getint("POLICY", "max_maker_offers_allowed")) crow = self.tmaker.db.execute( 'SELECT COUNT(DISTINCT counterparty) FROM orderbook;').fetchone() counterparty_count = crow['COUNT(DISTINCT counterparty)'] diff --git a/sendpayment.py b/sendpayment.py index 36886e16..bb2b440f 100644 --- a/sendpayment.py +++ b/sendpayment.py @@ -15,6 +15,7 @@ from joinmarket import validate_address, jm_single from joinmarket import get_log, choose_sweep_orders, choose_orders, \ pick_order, cheapest_order_choose, weighted_order_choose, debug_dump_object +from joinmarket.support import remove_makers_with_too_many_offers from joinmarket import Wallet, BitcoinCoreWallet, sync_wallet from joinmarket.wallet import estimate_tx_fee @@ -101,6 +102,10 @@ def __init__(self, taker): self.ignored_makers = [] def create_tx(self): + log.info('Removing makers with more than ' + + str(jm_single().config.getint("POLICY", "max_maker_offers_allowed")) + + ' offers as configured in joinmarket.cfg') + remove_makers_with_too_many_offers(self.taker.db, jm_single().config.getint("POLICY", "max_maker_offers_allowed")) crow = self.taker.db.execute( 'SELECT COUNT(DISTINCT counterparty) FROM orderbook;').fetchone() counterparty_count = crow['COUNT(DISTINCT counterparty)'] diff --git a/tumbler.py b/tumbler.py index 2a082341..7b45d468 100644 --- a/tumbler.py +++ b/tumbler.py @@ -17,6 +17,7 @@ from joinmarket import get_log, rand_norm_array, rand_pow_array, \ rand_exp_array, choose_orders, weighted_order_choose, choose_sweep_orders, \ debug_dump_object, get_irc_mchannels +from joinmarket.support import remove_makers_with_too_many_offers from joinmarket import Wallet from joinmarket.wallet import estimate_tx_fee @@ -178,6 +179,11 @@ def tumbler_choose_orders(self, if active_nicks is None: active_nicks = [] self.ignored_makers += nonrespondants + log.info('Removing makers with more than ' + + str(jm_single().config.getint("POLICY", "max_maker_offers_allowed")) + + ' offers as configured in joinmarket.cfg') + remove_makers_with_too_many_offers(self.taker.db, + jm_single().config.getint("POLICY", "max_maker_offers_allowed")) while True: orders, total_cj_fee = choose_orders( self.taker.db, cj_amount, makercount, weighted_order_choose, @@ -237,6 +243,11 @@ def create_tx(self): fee_for_tx = int(fee_for_tx / self.tx['makercount']) total_value = sum([addrval['value'] for addrval in utxos.values()]) while True: + log.info('Removing makers with more than ' + + str(jm_single().config.getint("POLICY", "max_maker_offers_allowed")) + + ' offers as configured in joinmarket.cfg') + remove_makers_with_too_many_offers(self.taker.db, + jm_single().config.getint("POLICY", "max_maker_offers_allowed")) orders, cj_amount, total_cj_fee = choose_sweep_orders( self.taker.db, total_value, fee_for_tx, self.tx['makercount'], weighted_order_choose,