diff --git a/jmclient/jmclient/__init__.py b/jmclient/jmclient/__init__.py index a739633..567be22 100644 --- a/jmclient/jmclient/__init__.py +++ b/jmclient/jmclient/__init__.py @@ -45,11 +45,12 @@ from .output import generate_podle_error_string, fmt_utxos, fmt_utxo,\ sweep_custom_change_warning from .schedule import (get_schedule, get_tumble_schedule, schedule_to_text, tweak_tumble_schedule, human_readable_schedule_entry, - schedule_to_text, NO_ROUNDING) + schedule_to_text, NO_ROUNDING, ScheduleGenerationErrorNoFunds) from .commitment_utils import get_utxo_info, validate_utxo_data, quit from .taker_utils import (tumbler_taker_finished_update, restart_waiter, restart_wait, get_tumble_log, direct_send, - tumbler_filter_orders_callback, direct_send) + tumbler_filter_orders_callback, direct_send, + get_total_tumble_amount) from .cli_options import (add_base_options, add_common_options, get_tumbler_parser, get_max_cj_fee_values, check_regtest, get_sendpayment_parser, diff --git a/jmclient/jmclient/taker_utils.py b/jmclient/jmclient/taker_utils.py index a8dfb72..a89fc60 100644 --- a/jmclient/jmclient/taker_utils.py +++ b/jmclient/jmclient/taker_utils.py @@ -229,6 +229,22 @@ def get_tumble_log(logsdir): tumble_log.addHandler(fileHandler) return tumble_log +def get_total_tumble_amount(mixdepth_balance_dict, schedule): + # calculating total coins that will be included in a tumble; + # in almost all cases all coins (unfrozen) in wallet will be tumbled, + # though it's technically possible with a very small mixdepthcount, to start + # at say m0, and only go through to 2 or 3, such that coins in 4 are untouched + # in phase 2 (after having been swept in phase 1). + used_mixdepths = set() + [used_mixdepths.add(x[0]) for x in schedule] + total_tumble_amount = int(0) + for i in used_mixdepths: + total_tumble_amount += mixdepth_balance_dict[i] + # Note; we assert since callers will have called `get_tumble_schedule`, + # which will already have thrown if no funds, so this would be a logic error. + assert total_tumble_amount > 0, "no coins to tumble." + return total_tumble_amount + def restart_wait(txid): """ Returns true only if the transaction txid is seen in the wallet, and confirmed (it must be an in-wallet transaction since it always diff --git a/jmclient/jmclient/wallet_rpc.py b/jmclient/jmclient/wallet_rpc.py index 4add2bd..8116cd6 100644 --- a/jmclient/jmclient/wallet_rpc.py +++ b/jmclient/jmclient/wallet_rpc.py @@ -25,7 +25,8 @@ from jmclient import Taker, jm_single, \ NotEnoughFundsException, get_tumble_log, get_tumble_schedule, \ get_schedule, get_tumbler_parser, schedule_to_text, \ tumbler_filter_orders_callback, tumbler_taker_finished_update, \ - validate_address, FidelityBondMixin + validate_address, FidelityBondMixin, \ + ScheduleGenerationErrorNoFunds from jmbase.support import get_log, utxostr_to_utxo jlog = get_log() @@ -1177,28 +1178,15 @@ class JMWalletDaemon(Service): jm_single().mincjamount = tumbler_options['mincjamount'] - # -- Check wallet balance ------------------------------------------ - - max_mix_depth = tumbler_options['mixdepthsrc'] + tumbler_options['mixdepthcount'] - - if tumbler_options['amtmixdepths'] > max_mix_depth: - max_mix_depth = tumbler_options['amtmixdepths'] - - max_mix_to_tumble = min(tumbler_options['mixdepthsrc'] + tumbler_options['mixdepthcount'], max_mix_depth) - - total_tumble_amount = int(0) - for i in range(tumbler_options['mixdepthsrc'], max_mix_to_tumble): - total_tumble_amount += self.services["wallet"].get_balance_by_mixdepth(verbose=False, minconfs=1)[i] - - if total_tumble_amount == 0: - raise NotEnoughCoinsForTumbler() - # -- Schedule generation ------------------------------------------- # Always generates a new schedule. No restart support for now. - schedule = get_tumble_schedule(tumbler_options, + try: + schedule = get_tumble_schedule(tumbler_options, destaddrs, self.services["wallet"].get_balance_by_mixdepth()) + except ScheduleGenerationErrorNoFunds: + raise NotEnoughCoinsForTumbler() logsdir = os.path.join(os.path.dirname(jm_single().config_location), "logs") diff --git a/scripts/tumbler.py b/scripts/tumbler.py index ef79a05..6340cb3 100755 --- a/scripts/tumbler.py +++ b/scripts/tumbler.py @@ -11,9 +11,9 @@ from jmclient import Taker, load_program_config, get_schedule,\ 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, \ - get_max_cj_fee_values + get_max_cj_fee_values, get_total_tumble_amount, ScheduleGenerationErrorNoFunds from jmclient.wallet_utils import DEFAULT_MIXDEPTH -from jmclient.schedule import ScheduleGenerationErrorNoFunds + from jmbase.support import get_log, jmprint, EXIT_SUCCESS, \ EXIT_FAILURE, EXIT_ARGERROR @@ -145,18 +145,10 @@ def main(): involved_parties = len(schedule) # own participation in each CJ for item in schedule: involved_parties += item[2] # number of total tumble counterparties - # calculating total coins that will be included in the tumble; - # in almost all cases all coins (unfrozen) in wallet will be tumbled, - # though it's technically possible with a very small mixdepthcount, to start - # at say m0, and only go through to 2 or 3, such that coins in 4 are untouched - # in phase 2 (after having been swept in phase 1). - used_mixdepths = set() - [used_mixdepths.add(x[0]) for x in schedule] - total_tumble_amount = int(0) - for i in used_mixdepths: - total_tumble_amount += wallet_service.get_balance_by_mixdepth()[i] - if total_tumble_amount == 0: - raise ValueError("No confirmed coins in the selected mixdepth(s). Quitting") + + total_tumble_amount = get_total_tumble_amount( + wallet.get_balance_by_mixdepth(), schedule) + exp_tx_fees_ratio = (involved_parties * fee_per_cp_guess) \ / total_tumble_amount if exp_tx_fees_ratio > 0.05: