Example #1
0
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)
Example #2
0
    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))