diff --git a/scripts/sendpayment.py b/scripts/sendpayment.py index d08516779..3d7cde610 100755 --- a/scripts/sendpayment.py +++ b/scripts/sendpayment.py @@ -18,6 +18,7 @@ get_sendpayment_parser, get_max_cj_fee_values, check_regtest, \ parse_payjoin_setup, send_payjoin, general_custom_change_warning, \ nonwallet_custom_change_warning, sweep_custom_change_warning, \ + get_banned_maker_ids, \ EngineError, check_and_start_tor from twisted.python.log import startLogging from jmbase.support import get_log, jmprint, \ @@ -389,6 +390,7 @@ def taker_finished(res, fromtx=False, waittime=0.0, txdetails=None): max_cj_fee=maxcjfee, callbacks=(filter_orders_callback, None, taker_finished), custom_change_address=custom_change, + banned_makers=get_banned_maker_ids(), change_label=options.changelabel) clientfactory = JMClientProtocolFactory(taker) diff --git a/scripts/tumbler.py b/scripts/tumbler.py index 59cc3ceda..2f92b2a33 100755 --- a/scripts/tumbler.py +++ b/scripts/tumbler.py @@ -7,7 +7,7 @@ from twisted.python.log import startLogging from jmclient import Taker, load_program_config, get_schedule,\ JMClientProtocolFactory, start_reactor, jm_single, get_wallet_path,\ - open_test_wallet_maybe, get_tumble_schedule,\ + open_test_wallet_maybe, get_tumble_schedule, get_banned_maker_ids, \ schedule_to_text, estimate_tx_fee, restart_waiter, WalletService,\ get_tumble_log, tumbler_taker_finished_update, check_regtest, \ tumbler_filter_orders_callback, validate_address, get_tumbler_parser, \ @@ -187,6 +187,7 @@ def taker_finished(res, fromtx=False, waittime=0.0, txdetails=None): maxcjfee, order_chooser=options['order_choose_fn'], callbacks=(filter_orders_callback, None, taker_finished), + banned_makers=get_banned_maker_ids(), tdestaddrs=destaddrs) clientfactory = JMClientProtocolFactory(taker) nodaemon = jm_single().config.getint("DAEMON", "no_daemon") diff --git a/src/jmclient/__init__.py b/src/jmclient/__init__.py index ab4c3ec09..e8587e5f8 100644 --- a/src/jmclient/__init__.py +++ b/src/jmclient/__init__.py @@ -28,6 +28,7 @@ validate_address, is_burn_destination, get_mchannels, get_blockchain_interface_instance, set_config, is_segwit_mode, is_native_segwit_mode, JMPluginService, get_interest_rate, + get_banned_maker_ids, get_bondless_makers_allowance, check_and_start_tor) from .blockchaininterface import (BlockchainInterface, RegtestBitcoinCoreInterface, BitcoinCoreInterface) diff --git a/src/jmclient/configure.py b/src/jmclient/configure.py index d0bf1d4d1..c3d82e67b 100644 --- a/src/jmclient/configure.py +++ b/src/jmclient/configure.py @@ -8,7 +8,7 @@ import sys from configparser import ConfigParser, NoOptionError from signal import SIGINT -from typing import Any, List, Optional, Tuple +from typing import Any, List, Optional, Set, Tuple import jmbitcoin as btc from jmbase.support import (get_log, joinmarket_alert, core_alert, debug_silence, @@ -363,6 +363,10 @@ def jm_single() -> AttributeDict: # A real number, i.e. 1 = 100%, 0.125 = 1/8 = 1 in every 8 makers on average will be bondless bondless_makers_allowance = """ + _DEFAULT_BONDLESS_MAKERS_ALLOWANCE + """ +# Allow blocking/ignoring makers by ID. These makers will not be included in taker coinjoins. +# Takes a list separated by commas. +# banned_maker_ids = J5Abcdefgh2,J5Ijklmnop3 + # To (strongly) disincentivize Sybil behaviour, the value assessment of the bond # is based on the (time value of the bond)^x where x is the bond_value_exponent here, # where x > 1. It is a real number (so written as a decimal). @@ -668,6 +672,12 @@ def get_bondless_makers_allowance() -> float: return float(global_singleton.config.get('POLICY', 'bondless_makers_allowance', fallback=_DEFAULT_BONDLESS_MAKERS_ALLOWANCE)) +def get_banned_maker_ids() -> Set[str]: + value = global_singleton.config.get('POLICY', 'banned_maker_ids', fallback='') + if value == '': + return set() + return set(value.split(',')) + def _remove_unwanted_default_settings(config: ConfigParser) -> None: for section in config.sections(): if section.startswith('MESSAGING:'): diff --git a/src/jmclient/taker.py b/src/jmclient/taker.py index 6a58af3de..64fecee9f 100644 --- a/src/jmclient/taker.py +++ b/src/jmclient/taker.py @@ -53,6 +53,7 @@ def __init__(self, tdestaddrs=None, custom_change_address=None, change_label=None, + banned_makers=None, ignored_makers=None): """`schedule`` must be a list of tuples: (see sample_schedule_for_testnet for explanation of syntax, also schedule.py module in this directory), @@ -111,6 +112,7 @@ def __init__(self, #who have not responded or behaved maliciously at any #stage of the protocol. self.ignored_makers = [] if not ignored_makers else ignored_makers + self.banned_makers = set([]) if not banned_makers else banned_makers #Used in attempts to complete with subset after second round failure: self.honest_makers = [] @@ -289,7 +291,7 @@ def filter_orderbook(self, orderbook, sweep=False): return False self.orderbook, self.total_cj_fee = choose_orders( orderbook, self.cjamount, self.n_counterparties, self.order_chooser, - self.ignored_makers, allowed_types=allowed_types, + self.banned_makers.union(self.ignored_makers), allowed_types=allowed_types, max_cj_fee=self.max_cj_fee) if self.orderbook is None: #Failure to get an orderbook means order selection failed @@ -380,7 +382,7 @@ def prepare_my_bitcoin_data(self): self.orderbook, self.cjamount, self.total_cj_fee = choose_sweep_orders( self.orderbook, total_value, self.total_txfee, self.n_counterparties, self.order_chooser, - self.ignored_makers, allowed_types=allowed_types, + self.banned_makers.union(self.ignored_makers), allowed_types=allowed_types, max_cj_fee=self.max_cj_fee) if not self.orderbook: self.taker_info_callback("ABORT", diff --git a/src/jmclient/wallet_rpc.py b/src/jmclient/wallet_rpc.py index 34ab55363..b9a64f0fe 100644 --- a/src/jmclient/wallet_rpc.py +++ b/src/jmclient/wallet_rpc.py @@ -15,7 +15,7 @@ WalletService, get_wallet_path, direct_send, \ open_test_wallet_maybe, wallet_display, SegwitLegacyWallet, \ SegwitWallet, get_daemon_serving_params, YieldGeneratorService, \ - create_wallet, get_max_cj_fee_values, \ + create_wallet, get_max_cj_fee_values, get_banned_maker_ids, \ StorageError, StoragePasswordError, JmwalletdWebSocketServerFactory, \ JmwalletdWebSocketServerProtocol, RetryableStorageError, \ SegwitWalletFidelityBonds, wallet_gettimelockaddress, \ @@ -1350,6 +1350,7 @@ def dummy_user_callback(rel, abs): self.taker = Taker(self.services["wallet"], schedule, max_cj_fee = max_cj_fee, + banned_makers=get_banned_maker_ids(), callbacks=(self.filter_orders_callback, None, self.taker_finished)) # TODO ; this makes use of a pre-existing hack to allow @@ -1482,6 +1483,7 @@ def dummy_user_callback(rel, abs): schedule, max_cj_fee=max_cj_fee, order_chooser=self.tumbler_options['order_choose_fn'], + banned_makers=get_banned_maker_ids(), callbacks=(self.filter_orders_callback_tumbler, None, self.taker_finished), tdestaddrs=destaddrs)