def test_run_both(setup_wallets, runtype): #hack to account for the fact that Carol does not even run #if the handshake is bad; this is done to force the reactor to stop. if runtype == "badhandshake": cs_single().num_entities_running = 1 #The setup of each test case is the same; the only difference is the #participant classes (only Alice for now) ac = alice_classes[runtype] if runtype in alice_classes else None cc = carol_classes[runtype] if runtype in carol_classes else None fail_alice_state = alice_recover_cases[ runtype] if runtype in alice_recover_cases else None fail_carol_state = carol_recover_cases[ runtype] if runtype in carol_recover_cases else None alices, carol_bbmb, carol_wallet = runcase(ac, cc, fail_alice_state, fail_carol_state) #test case function will only return on reactor shutdown; Alice and Carol #objects are set at the start, but are references so updated. #Check the wallet states reflect the expected updates. #TODO handle multiple alices with different amounts against one Carol. if runtype == "badhandshake": for a in alices: a.bbma = a.wallet.get_balance_by_mixdepth(verbose=False) expected_spent = reasonable_fee_maximum*4 + cs_single( ).config.getint("SERVER", "minimum_coinswap_fee") if runtype in alice_funds_not_moved_cases: for i, alice in enumerate(alices): assert alice.bbmb[0] == alice.bbma[0] elif runtype in ["cooperative", "cbadreceivetx4sig", "ra11", "rc8", "rc9"]: #in all of these cases Alice's payment is complete for i, alice in enumerate(alices): funds_spent = alice.bbmb[0] - alice.bbma[0] funds_received = alice.bbma[1] - alice.bbmb[1] assert funds_spent - funds_received <= expected_spent + reasonable_fee_maximum else: #Ensure Alice did not pay too much and only spent back to 0 depth for i, alice in enumerate(alices): assert alice.bbma[1] == 0 funds_spent = alice.bbmb[0] - alice.bbma[0] assert funds_spent <= expected_spent #Carol is handled a bit differently, since Carol instances are initiated on #the fly, we instead query the wallet object directly for the final balances. sync_wallet(carol_wallet) carol_bbma = carol_wallet.get_balance_by_mixdepth(verbose=False) if runtype in carol_funds_not_moved_cases: assert carol_bbma[0] >= carol_bbmb[0] assert carol_bbma[0] - carol_bbmb[0] <= reasonable_fee_maximum + cs_single( ).config.getint("SERVER", "minimum_coinswap_fee") elif runtype in ["cooperative", "rc9"]: funds_spent = carol_bbmb[0] - carol_bbma[0] funds_received = carol_bbma[1] - carol_bbmb[1] assert funds_received - funds_spent >= cs_single( ).config.getint("SERVER", "minimum_coinswap_fee") - reasonable_fee_maximum else: #All cases of backout and funds have moved assert carol_bbmb[1] == 0 #Here we assert carol did not lose money; the alice checks are sufficient #to ensure carol didn't get too much assert carol_bbma[0] - carol_bbmb[0] > 0
def test_run_both(setup_wallets, runtype): #hack to account for the fact that Carol does not even run #if the handshake is bad; this is done to force the reactor to stop. if runtype == "badhandshake": cs_single().num_entities_running = 1 #The setup of each test case is the same; the only difference is the #participant classes (only Alice for now) ac = alice_classes[runtype] if runtype in alice_classes else None cc = carol_classes[runtype] if runtype in carol_classes else None alices, carol_bbmb, carol_wallet = runcase(ac, cc) #test case function will only return on reactor shutdown; Alice and Carol #objects are set at the start, but are references so updated. #Check the wallet states reflect the expected updates. #TODO handle multiple alices with different amounts against one Carol. expected_amt = amounts[0] - reasonable_fee_maximum if runtype in alice_funds_not_moved_cases: for i, alice in enumerate(alices): assert alice.bbmb[0] == alice.bbma[0] else: for i, alice in enumerate(alices): funds_spent = alice.bbmb[0] - alice.bbma[0] funds_received = alice.bbma[1] - alice.bbmb[1] assert_funds_balance(expected_amt, funds_spent, funds_received) #Carol is handled a bit differently, since Carol instances are initiated on #the fly, we instead query the wallet object directly for the final balances. sync_wallet(carol_wallet) carol_bbma = carol_wallet.get_balance_by_mixdepth(verbose=False) if runtype in carol_funds_not_moved_cases: assert carol_bbma[0] == carol_bbmb[0] else: funds_spent = carol_bbmb[0] - carol_bbma[0] funds_received = carol_bbma[1] - carol_bbmb[1] assert_funds_balance(expected_amt, funds_spent, funds_received)
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
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 = Wallet(wallet_name, None, max_mix_depth, 6, wallet_dir=wallet_dir) else: while True: try: pwd = get_password("Enter wallet decryption passphrase: ") wallet = Wallet(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): cs_single().bc_interface.grab_coins(wallet.get_new_addr(0, 0, True), 2.0) wallet.index[0][0] -= 1 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: alice = aliceclass(wallet, 'alicestate', cpp, testing_mode=testing_mode) 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
extend_mixdepth=not maxmixdepth_configured, storepassword=(method == 'importprivkey')) 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 cs_single().config.options('POLICY'): cs_single().config.set('POLICY','listunspent_args', '[0]') sync_wallet(wallet, fast=options.fastsync) if method == 'showutxos': unsp = {} if options.showprivkey: for u, av in wallet.unspent.iteritems(): addr = av['address'] key = wallet.get_key_from_addr(addr) wifkey = btc.wif_compressed_privkey(key, vbyte=get_p2pk_vbyte()) unsp[u] = {'address': av['address'], 'value': av['value'], 'privkey': wifkey} else: unsp = wallet.unspent print(json.dumps(unsp, indent=4)) sys.exit(0)