Exemple #1
0
def open_wallet(path,
                ask_for_password=True,
                password=None,
                read_only=False,
                **kwargs):
    """
    Open the wallet file at path and return the corresponding wallet object.

    params:
        path: str, full path to wallet file
        ask_for_password: bool, if False password is assumed unset and user
            will not be asked to type it
        password: password for storage, ignored if ask_for_password is True
        read_only: bool, if True, open wallet in read-only mode
        kwargs: additional options to pass to wallet's init method

    returns:
        wallet object
    """
    if not os.path.isfile(path):
        raise Exception(
            "Failed to open wallet at '{}': not a file".format(path))

    if not Storage.is_storage_file(path):
        raise Exception("Failed to open wallet at '{}': not a valid joinmarket"
                        " wallet.\n\nIf this wallet is in the old json format "
                        "you need to convert it using the conversion script"
                        "at `scripts/convert_old_wallet.py`".format(path))

    if ask_for_password and Storage.is_encrypted_storage_file(path):
        while True:
            try:
                # do not try empty password, assume unencrypted on empty password
                pwd = get_password(
                    "Enter wallet decryption passphrase: ") or None
                storage = Storage(path, password=pwd, read_only=read_only)
            except StoragePasswordError:
                print("Wrong password, try again.")
                continue
            except Exception as e:
                print("Failed to load wallet, error message: " + repr(e))
                raise e
            break
    else:
        storage = Storage(path, password, read_only=read_only)

    wallet_cls = get_wallet_cls_from_storage(storage)
    wallet = wallet_cls(storage, **kwargs)
    wallet_sanity_check(wallet)
    return wallet
Exemple #2
0
def wallet_tool_main(wallet_root_path):
    """Main wallet tool script function; returned is a string (output or error)
    """
    parser = get_wallettool_parser()
    (options, args) = parser.parse_args()
    walletclass = SegwitWallet if jm_single().config.get(
        "POLICY", "segwit") == "true" else Wallet
    # if the index_cache stored in wallet.json is longer than the default
    # then set maxmixdepth to the length of index_cache
    maxmixdepth_configured = True
    if not options.maxmixdepth:
        maxmixdepth_configured = False
        options.maxmixdepth = 5

    noseed_methods = ['generate', 'recover']
    methods = ['display', 'displayall', 'summary', 'showseed', 'importprivkey',
               'history', 'showutxos']
    methods.extend(noseed_methods)
    noscan_methods = ['showseed', 'importprivkey', 'dumpprivkey', 'signmessage']

    if len(args) < 1:
        parser.error('Needs a wallet file or method')
        sys.exit(0)

    if args[0] in noseed_methods:
        method = args[0]
    else:
        seed = args[0]
        method = ('display' if len(args) == 1 else args[1].lower())
        if not os.path.exists(os.path.join(wallet_root_path, seed)):
            wallet = walletclass(seed, None, options.maxmixdepth,
                            options.gaplimit, extend_mixdepth= not maxmixdepth_configured,
                            storepassword=(method == 'importprivkey'),
                            wallet_dir=wallet_root_path)
        else:
            while True:
                try:
                    pwd = get_password("Enter wallet decryption passphrase: ")
                    wallet = walletclass(seed, pwd,
                            options.maxmixdepth,
                            options.gaplimit,
                            extend_mixdepth=not maxmixdepth_configured,
                            storepassword=(method == 'importprivkey'),
                            wallet_dir=wallet_root_path)
                except WalletError:
                    print("Wrong password, try again.")
                    continue
                except Exception as e:
                    print("Failed to load wallet, error message: " + repr(e))
                    sys.exit(0)
                break
        if method not in noscan_methods:
            # if nothing was configured, we override bitcoind's options so that
            # unconfirmed balance is included in the wallet display by default
            if 'listunspent_args' not in jm_single().config.options('POLICY'):
                jm_single().config.set('POLICY','listunspent_args', '[0]')
            sync_wallet(wallet, fast=options.fastsync)
    #Now the wallet/data is prepared, execute the script according to the method
    if method == "display":
        return wallet_display(wallet, options.gaplimit, options.showprivkey)
    elif method == "displayall":
        return wallet_display(wallet, options.gaplimit, options.showprivkey, displayall=True)
    elif method == "summary":
        return wallet_display(wallet, options.gaplimit, options.showprivkey, summarized=True)
    elif method == "history":
        if not isinstance(jm_single().bc_interface, BitcoinCoreInterface):
            print('showing history only available when using the Bitcoin Core ' +
                    'blockchain interface')
            sys.exit(0)
        else:
            return wallet_fetch_history(wallet, options)
    elif method == "generate":
        retval = wallet_generate_recover("generate", wallet_root_path)
        return retval if retval else "Failed"
    elif method == "recover":
        retval = wallet_generate_recover("recover", wallet_root_path)
        return retval if retval else "Failed"
    elif method == "showutxos":
        return wallet_showutxos(wallet, options.showprivkey)
    elif method == "showseed":
        return wallet_showseed(wallet)
    elif method == "dumpprivkey":
        return wallet_dumpprivkey(wallet, options.hd_path)
    elif method == "importprivkey":
        #note: must be interactive (security)
        wallet_importprivkey(wallet, options.mixdepth)
        return "Key import completed."
    elif method == "signmessage":
        return wallet_signmessage(wallet, options.hd_path, args[1])
Exemple #3
0
if __name__ == "__main__":
    load_coinjoinxt_config()
    wallet_name = sys.argv[1]
    serv, port = sys.argv[2:4]
    max_mix_depth = 3
    wallet_dir = os.path.join(cjxt_single().homedir, 'wallets')
    if not os.path.exists(os.path.join(wallet_dir, wallet_name)):
        wallet = SegwitWallet(wallet_name,
                              None,
                              max_mix_depth,
                              6,
                              wallet_dir=wallet_dir)
    else:
        while True:
            try:
                pwd = get_password("Enter wallet decryption passphrase: ")
                wallet = SegwitWallet(wallet_name,
                                      pwd,
                                      max_mix_depth,
                                      6,
                                      wallet_dir=wallet_dir)
            except WalletError:
                print("Wrong password, try again.")
                continue
            except Exception as e:
                print("Failed to load wallet, error message: " + repr(e))
                sys.exit(0)
            break
    """Uncomment this for auto-funding on regtest.
    if isinstance(cjxt_single().bc_interface, RegtestBitcoinCoreInterface):
        #funding the wallet with outputs specifically suitable for the starting point.
def main():
    tumble_log = get_tumble_log(logsdir)
    (options, args) = get_tumbler_parser().parse_args()
    options = vars(options)
    if len(args) < 1:
        parser.error('Needs a wallet file')
        sys.exit(0)
    load_program_config()
    #Load the wallet
    wallet_name = args[0]
    max_mix_depth = options['mixdepthsrc'] + options['mixdepthcount']
    if not os.path.exists(os.path.join('wallets', wallet_name)):
        wallet = SegwitWallet(wallet_name, None, max_mix_depth)
    else:
        while True:
            try:
                pwd = get_password("Enter wallet decryption passphrase: ")
                wallet = SegwitWallet(wallet_name, pwd, max_mix_depth)
            except WalletError:
                print("Wrong password, try again.")
                continue
            except Exception as e:
                print("Failed to load wallet, error message: " + repr(e))
                sys.exit(0)
            break
    if jm_single().config.get("BLOCKCHAIN",
                              "blockchain_source") == "electrum-server":
        jm_single().bc_interface.synctype = "with-script"
    sync_wallet(wallet, fast=options['fastsync'])

    #Parse options and generate schedule
    #Output information to log files
    jm_single().mincjamount = options['mincjamount']
    destaddrs = args[1:]
    print(destaddrs)
    #If the --restart flag is set we read the schedule
    #from the file, and filter out entries that are
    #already complete
    if options['restart']:
        res, schedule = get_schedule(
            os.path.join(logsdir, options['schedulefile']))
        if not res:
            print("Failed to load schedule, name: " +
                  str(options['schedulefile']))
            print("Error was: " + str(schedule))
            sys.exit(0)
        #This removes all entries that are marked as done
        schedule = [s for s in schedule if s[5] != 1]
        if isinstance(schedule[0][5], str) and len(schedule[0][5]) == 64:
            #ensure last transaction is confirmed before restart
            tumble_log.info("WAITING TO RESTART...")
            txid = schedule[0][5]
            restart_waiter(txid + ":0")  #add 0 index because all have it
            #remove the already-done entry (this connects to the other TODO,
            #probably better *not* to truncate the done-already txs from file,
            #but simplest for now.
            schedule = schedule[1:]
        elif schedule[0][5] != 0:
            print("Error: first schedule entry is invalid.")
            sys.exit(0)
        with open(os.path.join(logsdir, options['schedulefile']), "wb") as f:
            f.write(schedule_to_text(schedule))
        tumble_log.info("TUMBLE RESTARTING")
    else:
        #Create a new schedule from scratch
        schedule = get_tumble_schedule(options, destaddrs)
        tumble_log.info("TUMBLE STARTING")
        with open(os.path.join(logsdir, options['schedulefile']), "wb") as f:
            f.write(schedule_to_text(schedule))
        print("Schedule written to logs/" + options['schedulefile'])
    tumble_log.info("With this schedule: ")
    tumble_log.info(pprint.pformat(schedule))

    print("Progress logging to logs/TUMBLE.log")

    def filter_orders_callback(orders_fees, cjamount):
        """Decide whether to accept fees
        """
        return tumbler_filter_orders_callback(orders_fees, cjamount, taker,
                                              options)

    def taker_finished(res, fromtx=False, waittime=0.0, txdetails=None):
        """on_finished_callback for tumbler; processing is almost entirely
        deferred to generic taker_finished in tumbler_support module, except
        here reactor signalling.
        """
        sfile = os.path.join(logsdir, options['schedulefile'])
        tumbler_taker_finished_update(taker, sfile, tumble_log, options, res,
                                      fromtx, waittime, txdetails)
        if not fromtx:
            reactor.stop()
        elif fromtx != "unconfirmed":
            reactor.callLater(waittime * 60,
                              clientfactory.getClient().clientStart)

    #to allow testing of confirm/unconfirm callback for multiple txs
    if isinstance(jm_single().bc_interface, RegtestBitcoinCoreInterface):
        jm_single().bc_interface.tick_forward_chain_interval = 10
        jm_single().bc_interface.simulating = True
        jm_single().maker_timeout_sec = 15

    #instantiate Taker with given schedule and run
    taker = Taker(wallet,
                  schedule,
                  order_chooser=weighted_order_choose,
                  callbacks=(filter_orders_callback, None, taker_finished),
                  tdestaddrs=destaddrs)
    clientfactory = JMClientProtocolFactory(taker)
    nodaemon = jm_single().config.getint("DAEMON", "no_daemon")
    daemon = True if nodaemon == 1 else False
    if jm_single().config.get("BLOCKCHAIN",
                              "network") in ["regtest", "testnet"]:
        startLogging(sys.stdout)
    start_reactor(jm_single().config.get("DAEMON", "daemon_host"),
                  jm_single().config.getint("DAEMON", "daemon_port"),
                  clientfactory,
                  daemon=daemon)
Exemple #5
0
def main():
    parser = get_sendpayment_parser()
    (options, args) = parser.parse_args()
    load_program_config()
    if options.schedule == '' and len(args) < 3:
        parser.error('Needs a wallet, amount and destination address')
        sys.exit(0)

    #without schedule file option, use the arguments to create a schedule
    #of a single transaction
    sweeping = False
    if options.schedule == '':
        #note that sendpayment doesn't support fractional amounts, fractions throw
        #here.
        amount = int(args[1])
        if amount == 0:
            sweeping = True
        destaddr = args[2]
        mixdepth = options.mixdepth
        addr_valid, errormsg = validate_address(destaddr)
        if not addr_valid:
            print('ERROR: Address invalid. ' + errormsg)
            return
        schedule = [[
            options.mixdepth, amount, options.makercount, destaddr, 0.0, 0
        ]]
    else:
        result, schedule = get_schedule(options.schedule)
        if not result:
            log.info(
                "Failed to load schedule file, quitting. Check the syntax.")
            log.info("Error was: " + str(schedule))
            sys.exit(0)
        mixdepth = 0
        for s in schedule:
            if s[1] == 0:
                sweeping = True
            #only used for checking the maximum mixdepth required
            mixdepth = max([mixdepth, s[0]])

    wallet_name = args[0]

    #to allow testing of confirm/unconfirm callback for multiple txs
    if isinstance(jm_single().bc_interface, RegtestBitcoinCoreInterface):
        jm_single().bc_interface.tick_forward_chain_interval = 10
        jm_single().bc_interface.simulating = True
        jm_single().maker_timeout_sec = 15

    chooseOrdersFunc = None
    if options.pickorders:
        chooseOrdersFunc = pick_order
        if sweeping:
            print('WARNING: You may have to pick offers multiple times')
            print('WARNING: due to manual offer picking while sweeping')
    elif options.choosecheapest:
        chooseOrdersFunc = cheapest_order_choose
    else:  # choose randomly (weighted)
        chooseOrdersFunc = weighted_order_choose

    # Dynamically estimate a realistic fee if it currently is the default value.
    # At this point we do not know even the number of our own inputs, so
    # we guess conservatively with 2 inputs and 2 outputs each.
    if options.txfee == -1:
        options.txfee = max(options.txfee,
                            estimate_tx_fee(2, 2, txtype="p2sh-p2wpkh"))
        log.debug("Estimated miner/tx fee for each cj participant: " +
                  str(options.txfee))
    assert (options.txfee >= 0)

    log.debug('starting sendpayment')

    if not options.userpcwallet:
        #maxmixdepth in the wallet is actually the *number* of mixdepths (so misnamed);
        #to ensure we have enough, must be at least (requested index+1)
        max_mix_depth = max([mixdepth + 1, options.amtmixdepths])
        if not os.path.exists(os.path.join('wallets', wallet_name)):
            wallet = get_wallet_cls()(wallet_name, None, max_mix_depth,
                                      options.gaplimit)
        else:
            while True:
                try:
                    pwd = get_password("Enter wallet decryption passphrase: ")
                    wallet = get_wallet_cls()(wallet_name, pwd, max_mix_depth,
                                              options.gaplimit)
                except WalletError:
                    print("Wrong password, try again.")
                    continue
                except Exception as e:
                    print("Failed to load wallet, error message: " + repr(e))
                    sys.exit(0)
                break
    else:
        wallet = BitcoinCoreWallet(fromaccount=wallet_name)
    if jm_single().config.get(
            "BLOCKCHAIN", "blockchain_source"
    ) == "electrum-server" and options.makercount != 0:
        jm_single().bc_interface.synctype = "with-script"
    #wallet sync will now only occur on reactor start if we're joining.
    sync_wallet(wallet, fast=options.fastsync)
    if options.makercount == 0:
        if isinstance(wallet, BitcoinCoreWallet):
            raise NotImplementedError(
                "Direct send only supported for JM wallets")
        direct_send(wallet, amount, mixdepth, destaddr, options.answeryes)
        return

    def filter_orders_callback(orders_fees, cjamount):
        orders, total_cj_fee = orders_fees
        log.info("Chose these orders: " + pprint.pformat(orders))
        log.info('total cj fee = ' + str(total_cj_fee))
        total_fee_pc = 1.0 * total_cj_fee / cjamount
        log.info('total coinjoin fee = ' +
                 str(float('%.3g' % (100.0 * total_fee_pc))) + '%')
        WARNING_THRESHOLD = 0.02  # 2%
        if total_fee_pc > WARNING_THRESHOLD:
            log.info('\n'.join(['=' * 60] * 3))
            log.info('WARNING   ' * 6)
            log.info('\n'.join(['=' * 60] * 1))
            log.info(
                'OFFERED COINJOIN FEE IS UNUSUALLY HIGH. DOUBLE/TRIPLE CHECK.')
            log.info('\n'.join(['=' * 60] * 1))
            log.info('WARNING   ' * 6)
            log.info('\n'.join(['=' * 60] * 3))
        if not options.answeryes:
            if raw_input('send with these orders? (y/n):')[0] != 'y':
                return False
        return True

    def taker_finished(res, fromtx=False, waittime=0.0, txdetails=None):
        if fromtx == "unconfirmed":
            #If final entry, stop *here*, don't wait for confirmation
            if taker.schedule_index + 1 == len(taker.schedule):
                reactor.stop()
            return
        if fromtx:
            if res:
                txd, txid = txdetails
                taker.wallet.remove_old_utxos(txd)
                taker.wallet.add_new_utxos(txd, txid)
                reactor.callLater(waittime * 60,
                                  clientfactory.getClient().clientStart)
            else:
                #a transaction failed; just stop
                reactor.stop()
        else:
            if not res:
                log.info("Did not complete successfully, shutting down")
            #Should usually be unreachable, unless conf received out of order;
            #because we should stop on 'unconfirmed' for last (see above)
            else:
                log.info("All transactions completed correctly")
            reactor.stop()

    taker = Taker(wallet,
                  schedule,
                  order_chooser=chooseOrdersFunc,
                  callbacks=(filter_orders_callback, None, taker_finished))
    clientfactory = JMClientProtocolFactory(taker)
    nodaemon = jm_single().config.getint("DAEMON", "no_daemon")
    daemon = True if nodaemon == 1 else False
    if jm_single().config.get("BLOCKCHAIN",
                              "network") in ["regtest", "testnet"]:
        startLogging(sys.stdout)
    start_reactor(jm_single().config.get("DAEMON", "daemon_host"),
                  jm_single().config.getint("DAEMON", "daemon_port"),
                  clientfactory,
                  daemon=daemon)
Exemple #6
0
def main_cs(test_data=None):
    #twisted logging (TODO disable for non-debug runs)
    if test_data:
        wallet_name, args, options, use_ssl, alt_class, alt_c_class, fail_alice_state, fail_carol_state = test_data
        server, port, usessl = parse_server_string(options.serverport)
    else:
        parser = get_coinswap_parser()
        (options, args) = parser.parse_args()
        #Will only be used by client
        server, port, usessl = parse_server_string(options.serverport)
        if options.checkonly:
            #no need for any more data; just query
            alice_client = CoinSwapJSONRPCClient(server[2:],
                                                 port,
                                                 usessl=usessl)
            reactor.callWhenRunning(alice_client.send_poll_unsigned, "status",
                                    print_status)
            reactor.run()
            return
        log.startLogging(sys.stdout)
        load_coinswap_config()
        wallet_name = args[0]
    #depth 0: spend in, depth 1: receive out, depth 2: for backout transactions.
    max_mix_depth = 3
    wallet_dir = os.path.join(cs_single().homedir, 'wallets')
    if not os.path.exists(os.path.join(wallet_dir, wallet_name)):
        wallet = SegwitWallet(wallet_name,
                              None,
                              max_mix_depth,
                              6,
                              wallet_dir=wallet_dir)
    else:
        while True:
            try:
                pwd = get_password("Enter wallet decryption passphrase: ")
                wallet = SegwitWallet(wallet_name,
                                      pwd,
                                      max_mix_depth,
                                      6,
                                      wallet_dir=wallet_dir)
            except WalletError:
                print("Wrong password, try again.")
                continue
            except Exception as e:
                print("Failed to load wallet, error message: " + repr(e))
                sys.exit(0)
            break
    #for testing main script (not test framework), need funds.
    if not test_data and isinstance(cs_single().bc_interface,
                                    RegtestBitcoinCoreInterface):
        for i in range(3):
            cs_single().bc_interface.grab_coins(
                wallet.get_new_addr(0, 0, True), 2.0)
        wallet.index[0][0] -= 3
        time.sleep(3)
    sync_wallet(wallet, fast=options.fastsync)
    if test_data:
        cs_single().bc_interface.wallet_synced = True
    wallet.used_coins = None
    if options.serve:
        #sanity check that client params were not provided:
        if len(args) > 1:
            print("Extra parameters provided for running as server. "
                  "Are you sure you didn't want to run as client?")
            sys.exit(0)
        if not test_data:
            main_server(options, wallet)
        else:
            main_server(
                options, wallet, {
                    'use_ssl': use_ssl,
                    'alt_c_class': alt_c_class,
                    'fail_carol_state': fail_carol_state
                })
            return wallet.get_balance_by_mixdepth()
        return
    if not options.recover:
        target_amount = int(args[1])
        #Reset the targetting for backout transactions
        #TODO must be removed/changed for updated fees handling
        oldtarget = cs_single().config.get("POLICY", "tx_fees")
        newtarget = cs_single().config.getint("POLICY", "backout_fee_target")
        multiplier = float(cs_single().config.get("POLICY",
                                                  "backout_fee_multiplier"))
        cs_single().config.set("POLICY", "tx_fees", str(newtarget))
        tx23fee = estimate_tx_fee((1, 2, 2), 1, txtype='p2shMofN')
        tx23fee = int(multiplier * tx23fee)
        tx24_recipient_amount = target_amount - tx23fee
        tx35_recipient_amount = target_amount - tx23fee
        cs_single().config.set("POLICY", "tx_fees", oldtarget)
    #to allow testing of confirm/unconfirm callback for multiple txs
    if isinstance(cs_single().bc_interface, RegtestBitcoinCoreInterface):
        cs_single().bc_interface.tick_forward_chain_interval = 2
        cs_single().bc_interface.simulating = True
        cs_single().config.set("BLOCKCHAIN", "notify_port", "62652")
        cs_single().config.set("BLOCKCHAIN", "rpc_host", "127.0.0.2")

    #if restart option selected, read state and backout
    if options.recover:
        session_id = options.recover
        alice = CoinSwapAlice(wallet, 'alicestate')
        alice.bbmb = wallet.get_balance_by_mixdepth(verbose=False)
        alice.load(sessionid=session_id)
        alice.backout("Recovering from shutdown")
        reactor.run()
        return
    if len(args) > 2:
        tx5address = args[2]
        if not validate_address(tx5address):
            print("Invalid address: ", tx5address)
            sys.exit(0)
    else:
        #Our destination address should be in a separate mixdepth
        tx5address = wallet.get_new_addr(1, 1, True)
    #instantiate the parameters, but don't yet have the ephemeral pubkeys
    #or destination addresses.
    #TODO figure out best estimate incl. priority
    btcfee_est = estimate_tx_fee((1, 2, 2), 1, txtype='p2shMofN')
    cpp = CoinSwapPublicParameters(base_amount=target_amount,
                                   bitcoin_fee=btcfee_est)
    cpp.set_addr_data(addr5=tx5address)
    testing_mode = True if test_data else False
    aliceclass = alt_class if test_data and alt_class else CoinSwapAlice
    if test_data and fail_alice_state:
        alice = aliceclass(wallet,
                           'alicestate',
                           cpp,
                           testing_mode=testing_mode,
                           fail_state=fail_alice_state)
    else:
        if testing_mode or options.checkfee:
            alice = aliceclass(wallet,
                               'alicestate',
                               cpp,
                               testing_mode=testing_mode)
        else:
            alice = aliceclass(wallet,
                               'alicestate',
                               cpp,
                               testing_mode=testing_mode,
                               fee_checker="cli")

    alice_client = CoinSwapJSONRPCClient(server[2:], port, alice.sm.tick,
                                         alice.backout, usessl)
    alice.set_jsonrpc_client(alice_client)
    reactor.callWhenRunning(alice_client.send_poll_unsigned, "status",
                            alice.check_server_status)
    if not test_data:
        reactor.run()
    if test_data:
        return alice
Exemple #7
0
def main_cs(test_data=None):
    #twisted logging (TODO disable for non-debug runs)
    if test_data:
        wallet_name, args, options, use_ssl, alt_class, alt_c_class = test_data
    else:
        log.startLogging(sys.stdout)
        #Joinmarket wallet
        parser = get_coinswap_parser()
        (options, args) = parser.parse_args()
        load_coinswap_config()
        wallet_name = args[0]
    #depth 0: spend in, depth 1: receive out, depth 2: for backout transactions.
    max_mix_depth = 3
    if not os.path.exists(os.path.join('wallets', wallet_name)):
        wallet = Wallet(wallet_name, None, max_mix_depth, 6)
    else:
        while True:
            try:
                pwd = get_password("Enter wallet decryption passphrase: ")
                wallet = Wallet(wallet_name, pwd, max_mix_depth, 6)
            except WalletError:
                print("Wrong password, try again.")
                continue
            except Exception as e:
                print("Failed to load wallet, error message: " + repr(e))
                sys.exit(0)
            break
    #for testing main script (not test framework), need funds.
    if not test_data and isinstance(cs_single().bc_interface,
                                    RegtestBitcoinCoreInterface):
        cs_single().bc_interface.grab_coins(wallet.get_new_addr(0, 0), 2.0)
        time.sleep(3)
    sync_wallet(wallet, fast=options.fastsync)
    wallet.used_coins = None
    if options.serve:
        #sanity check that client params were not provided:
        if len(args) > 1:
            print("Extra parameters provided for running as server. "
                  "Are you sure you didn't want to run as client?")
            sys.exit(0)
        if not test_data:
            main_server(options, wallet)
        else:
            main_server(options, wallet, {
                'use_ssl': use_ssl,
                'alt_c_class': alt_c_class
            })
            return wallet.get_balance_by_mixdepth()
        return
    tx01_amount = int(args[1])
    #Reset the targetting for backout transactions
    oldtarget = cs_single().config.get("POLICY", "tx_fees")
    newtarget = cs_single().config.getint("POLICY", "backout_fee_target")
    multiplier = float(cs_single().config.get("POLICY",
                                              "backout_fee_multiplier"))
    cs_single().config.set("POLICY", "tx_fees", str(newtarget))
    tx23fee = estimate_tx_fee((1, 2, 2), 1, txtype='p2shMofN')
    tx23fee = int(multiplier * tx23fee)
    tx24_recipient_amount = tx01_amount - tx23fee
    tx35_recipient_amount = tx01_amount - tx23fee
    cs_single().config.set("POLICY", "tx_fees", oldtarget)
    #to allow testing of confirm/unconfirm callback for multiple txs
    if isinstance(cs_single().bc_interface, RegtestBitcoinCoreInterface):
        cs_single().bc_interface.tick_forward_chain_interval = 2
        cs_single().bc_interface.simulating = True
        cs_single().config.set("BLOCKCHAIN", "notify_port", "62652")
        cs_single().config.set("BLOCKCHAIN", "rpc_host", "127.0.0.2")

    #if restart option selected, read state and backout
    if options.recover:
        session_id = options.recover
        alice = CoinSwapAlice(wallet, 'alicestate')
        alice.bbmb = wallet.get_balance_by_mixdepth(verbose=False)
        alice.load(sessionid=session_id)
        alice.backout("Recovering from shutdown")
        reactor.run()
        return
    if len(args) > 2:
        tx5address = args[2]
        if not validate_address(tx5address):
            print("Invalid address: ", tx5address)
            sys.exit(0)
    else:
        #Our destination address should be in a separate mixdepth
        tx5address = wallet.get_new_addr(1, 1)
    #instantiate the parameters, but don't yet have the ephemeral pubkeys
    #or destination addresses.
    cpp = CoinSwapPublicParameters(tx01_amount, tx24_recipient_amount,
                                   tx35_recipient_amount)
    #Alice must set the unique identifier for this run.
    cpp.set_session_id()
    cpp.set_tx5_address(tx5address)
    testing_mode = True if test_data else False
    aliceclass = alt_class if test_data and alt_class else CoinSwapAlice
    alice = aliceclass(wallet, 'alicestate', cpp, testing_mode=testing_mode)
    scheme, server, port = options.serverport.split(":")
    print("got this scheme, server, port: ", scheme, server, port)
    if scheme == "https":
        usessl = True
    elif scheme == "http":
        usessl = False
    else:
        print("Invalid server string: ", options.serverport)
        sys.exit(0)
    if not server[:2] == "//":
        print("Invalid server string: ", options.serverport)
    alice_client = CoinSwapJSONRPCClient(server[2:], port, alice.sm.tick,
                                         alice.backout, usessl)
    alice.set_jsonrpc_client(alice_client)
    reactor.callWhenRunning(alice.sm.tick)
    if not test_data:
        reactor.run()
    if test_data:
        return alice