def test_simple_payjoin(monkeypatch, tmpdir, setup_cj, wallet_cls, wallet_structures, mean_amt): def raise_exit(i): raise Exception("sys.exit called") monkeypatch.setattr(sys, 'exit', raise_exit) wallet_services = [] wallet_services.append(make_wallets_to_list(make_wallets( 1, wallet_structures=[wallet_structures[0]], mean_amt=mean_amt, wallet_cls=wallet_cls[0]))[0]) wallet_services.append(make_wallets_to_list(make_wallets( 1, wallet_structures=[wallet_structures[1]], mean_amt=mean_amt, wallet_cls=wallet_cls[1]))[0]) jm_single().bc_interface.tickchain() sync_wallets(wallet_services) # For accounting purposes, record the balances # at the start. msb = getbals(wallet_services[0], 0) tsb = getbals(wallet_services[1], 0) cj_amount = int(1.1 * 10**8) maker = P2EPMaker(wallet_services[0], 0, cj_amount) destaddr = maker.destination_addr monkeypatch.setattr(maker, 'user_check', dummy_user_check) # TODO use this to sanity check behaviour # in presence of the rest of the joinmarket orderbook. orderbook = create_orderbook([maker]) assert len(orderbook) == 1 # mixdepth, amount, counterparties, dest_addr, waittime; # in payjoin we only pay attention to the first two entries. schedule = [(0, cj_amount, 1, destaddr, 0)] taker = create_taker(wallet_services[-1], schedule, monkeypatch) monkeypatch.setattr(taker, 'user_check', dummy_user_check) init_data = taker.initialize(orderbook) # the P2EPTaker.initialize() returns: # (True, self.cjamount, "p2ep", "p2ep", {self.p2ep_receiver_nick:{}}) assert init_data[0], "taker.initialize error" active_orders = init_data[4] assert len(active_orders.keys()) == 1 response = taker.receive_utxos(list(active_orders.keys())) assert response[0], "taker receive_utxos error" # test for validity of signed fallback transaction; requires 0.17; # note that we count this as an implicit test of fallback mode. res = jm_single().bc_interface.rpc('testmempoolaccept', [[response[2]]]) assert res[0]["allowed"], "Proposed transaction was rejected from mempool." maker_response = maker.on_tx_received("faketaker", response[2]) if not maker_response[0]: print("maker on_tx_received failed, reason: ", maker_response[1]) assert False taker_response = taker.on_tx_received("fakemaker", maker_response[2]) if not taker_response[1] == "OK": print("Failure in taker on_tx_received, reason: ", taker_response[1]) assert False # Although the above OK is proof that a transaction went through, # it doesn't prove it was a good transaction! Here do balance checks: assert final_checks(wallet_services, cj_amount, taker.total_txfee, tsb, msb)
def do_test_payment(self, wc1, wc2, amt=1.1): wallet_structures = [self.wallet_structure] * 2 wallet_cls = (wc1, wc2) self.wallet_services = [] self.wallet_services.append(make_wallets_to_list(make_wallets( 1, wallet_structures=[wallet_structures[0]], mean_amt=self.mean_amt, wallet_cls=wallet_cls[0]))[0]) self.wallet_services.append(make_wallets_to_list(make_wallets( 1, wallet_structures=[wallet_structures[1]], mean_amt=self.mean_amt, wallet_cls=wallet_cls[1]))[0]) jm_single().bc_interface.tickchain() sync_wallets(self.wallet_services) # For accounting purposes, record the balances # at the start. self.rsb = getbals(self.wallet_services[0], 0) self.ssb = getbals(self.wallet_services[1], 0) self.cj_amount = int(amt * 10**8) def cbStopListening(): return self.port.stopListening() b78rm = JMBIP78ReceiverManager(self.wallet_services[0], 0, self.cj_amount, 47083) resource = DummyBIP78ReceiverResource(jmprint, cbStopListening, b78rm) self.site = Site(resource) self.site.displayTracebacks = False # NB The connectivity aspects of the onion-based BIP78 setup # are time heavy. This server is TCP only. self.port = reactor.listenTCP(47083, self.site) self.addCleanup(cbStopListening) # setup of spender bip78_btc_amount = amount_to_btc(amount_to_sat(self.cj_amount)) bip78_uri = encode_bip21_uri(str(b78rm.receiving_address), {"amount": bip78_btc_amount, "pj": b"http://127.0.0.1:47083"}, safe=":/") self.manager = parse_payjoin_setup(bip78_uri, self.wallet_services[1], 0) self.manager.mode = "testing" success, msg = make_payment_psbt(self.manager) assert success, msg params = make_payjoin_request_params(self.manager) # avoiding backend daemon (testing only jmclient code here), # we send the http request manually: serv = b"http://127.0.0.1:47083" agent = get_nontor_agent() body = BytesProducer(self.manager.initial_psbt.to_base64().encode("utf-8")) url_parts = list(wrapped_urlparse(serv)) url_parts[4] = urlencode(params).encode("utf-8") destination_url = urlparse.urlunparse(url_parts) d = agent.request(b"POST", destination_url, Headers({"Content-Type": ["text/plain"]}), bodyProducer=body) d.addCallback(bip78_receiver_response, self.manager) return d
def setUp(self): load_test_config() self.clean_out_wallet_files() jm_single().bc_interface.tick_forward_chain_interval = 5 jm_single().bc_interface.simulate_blocks() # a client connnection object which is often but not always # instantiated: self.client_connector = None # start the daemon; note we are using tcp connections # to avoid storing certs in the test env. # TODO change that. self.daemon = JMWalletDaemonT(self.dport, self.wss_port, tls=False) self.daemon.auth_disabled = False # because we sync and start the wallet service manually here # (and don't use wallet files yet), we won't have set a wallet name, # so we set it here: self.daemon.wallet_name = self.get_wallet_file_name(1) r, s = self.daemon.startService() self.listener_rpc = r self.listener_ws = s wallet_structures = [self.wallet_structure] * 2 # note: to test fidelity bond wallets we should add the argument # `wallet_cls=SegwitWalletFidelityBonds` here, but it slows the # test down from 9 seconds to 1 minute 40s, which is too slow # to be acceptable. TODO: add a test with FB by speeding up # the sync for test, by some means or other. self.daemon.services["wallet"] = make_wallets_to_list( make_wallets(1, wallet_structures=[wallet_structures[0]], mean_amt=self.mean_amt, wallet_cls=SegwitWalletFidelityBonds))[0] jm_single().bc_interface.tickchain() sync_wallets([self.daemon.services["wallet"]]) # dummy tx example to force a notification event: self.test_tx = CTransaction.deserialize(hextobin(test_tx_hex_1))