def test_listutxos_and_freeze(self):
     self.daemon.auth_disabled = True
     agent = get_nontor_agent()
     pre_addr = self.get_route_root()
     pre_addr += "/wallet/"
     pre_addr += self.daemon.wallet_name
     addr = pre_addr + "/utxos"
     addr = addr.encode()
     yield self.do_request(agent, b"GET", addr, None,
                           self.process_listutxos_response)
     # Test of freezing is currently very primitive: we only
     # check that the action was accepted; a full test would
     # involve checking that spending the coin works or doesn't
     # work, as expected.
     addr = pre_addr + "/freeze"
     addr = addr.encode()
     utxostr = self.mixdepth1_utxos[0]["utxo"]
     body = BytesProducer(
         json.dumps({
             "utxo-string": utxostr,
             "freeze": True
         }).encode())
     yield self.do_request(agent, b"POST", addr, body,
                           self.process_utxo_freeze)
     body = BytesProducer(
         json.dumps({
             "utxo-string": utxostr,
             "freeze": False
         }).encode())
     yield self.do_request(agent, b"POST", addr, body,
                           self.process_utxo_freeze)
 def test_session(self):
     agent = get_nontor_agent()
     addr = self.get_route_root()
     addr += "/session"
     addr = addr.encode()
     yield self.do_request(agent, b"GET", addr, None,
                           self.process_session_response)
 def test_direct_send_and_display_wallet(self):
     """ First spend a coin, then check the balance
     via the display wallet output.
     """
     self.daemon.auth_disabled = True
     agent = get_nontor_agent()
     addr = self.get_route_root()
     addr += "/wallet/"
     addr += self.daemon.wallet_name
     addr += "/taker/direct-send"
     addr = addr.encode()
     body = BytesProducer(
         json.dumps({
             "mixdepth": "1",
             "amount_sats": "100000000",
             "destination": "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br"
         }).encode())
     yield self.do_request(agent, b"POST", addr, body,
                           self.process_direct_send_response)
     # before querying the wallet display, set a label to check:
     labeladdr = self.daemon.services["wallet"].get_addr(0, 0, 0)
     self.daemon.services["wallet"].set_address_label(
         labeladdr, "test-wallet-rpc-label")
     # force the wallet service txmonitor to wake up, to see the new
     # tx before querying /display:
     self.daemon.services["wallet"].transaction_monitor()
     addr = self.get_route_root()
     addr += "/wallet/"
     addr += self.daemon.wallet_name
     addr += "/display"
     addr = addr.encode()
     yield self.do_request(agent, b"GET", addr, None,
                           self.process_wallet_display_response)
 def test_get_seed(self):
     self.daemon.auth_disabled = True
     agent = get_nontor_agent()
     addr = self.get_route_root()
     addr += "/wallet/"
     addr += self.daemon.wallet_name
     addr += "/getseed"
     addr = addr.encode()
     yield self.do_request(agent, b"GET", addr, None,
                           self.process_get_seed_response)
 def test_gettimelockaddress(self):
     self.daemon.auth_disabled = True
     agent = get_nontor_agent()
     addr = self.get_route_root()
     addr += "/wallet/"
     addr += self.daemon.wallet_name
     addr += "/address/timelock/new/2023-02"
     addr = addr.encode()
     yield self.do_request(agent, b"GET", addr, None,
                           self.process_new_addr_response)
Example #6
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 test_getaddress(self):
     """ Tests that we can source a valid address
     for deposits using getaddress.
     """
     self.daemon.auth_disabled = True
     agent = get_nontor_agent()
     addr = self.get_route_root()
     addr += "/wallet/"
     addr += self.daemon.wallet_name
     addr += "/address/new/3"
     addr = addr.encode()
     yield self.do_request(agent, b"GET", addr, None,
                           self.process_new_addr_response)
Example #8
0
    def getAgentDestination(self, server, params=None):
        tor_url_data = is_hs_uri(server)
        if tor_url_data:
            # note: SSL over Tor not supported at the moment:
            agent = get_tor_agent(self.socks5_host, self.socks5_port)
        else:
            agent = get_nontor_agent(self.tls_whitelist)

        destination_url = server.encode("utf-8")
        url_parts = list(wrapped_urlparse(destination_url))
        if params:
            url_parts[4] = urlencode(params).encode("utf-8")
        destination_url = urlparse.urlunparse(url_parts)
        return (agent, destination_url)
    def test_maker_start_stop(self):
        """ Tests that we can start the maker service.
        As for the taker coinjoin test, this is currently
        a simple/artificial test, only checking return status
        codes and state updates, but not checking that an actual
        backend maker service is started.
        """
        self.daemon.auth_disabled = True
        agent = get_nontor_agent()
        addr_start = self.get_route_root()
        addr_start += "/wallet/"
        addr_start += self.daemon.wallet_name
        addr = addr_start + "/maker/start"
        addr = addr.encode()
        body = BytesProducer(
            json.dumps({
                "txfee": "0",
                "cjfee_a": "1000",
                "cjfee_r": "0.0002",
                "ordertype": "reloffer",
                "minsize": "1000000"
            }).encode())
        yield self.do_request(agent, b"POST", addr, body,
                              self.process_maker_start)

        # For the second phase, since we are not currently processing
        # via actual backend connections, we need to mock the client
        # protocol instance that requests shutdown of all message channels:
        class DummyMakerClientProto(object):
            def request_mc_shutdown(self):
                jlog.info("Message channel shutdown request registered.")
        self.daemon.services["maker"].clientfactory.proto_client = \
            DummyMakerClientProto()
        addr = addr_start + "/maker/stop"
        addr = addr.encode()
        yield self.do_request(agent, b"GET", addr, None,
                              self.process_maker_stop)
 def test_do_coinjoin(self):
     """ This slightly weird test curently only
     tests *requesting* a coinjoin; because there are
     no makers running in the test suite, the Taker will
     give up early due to the empty orderbook, but that is
     OK since this API call only makes the request.
     """
     self.daemon.auth_disabled = True
     # in normal operations, the RPC call will trigger
     # the jmclient to connect to an *existing* daemon
     # that was created on startup, but here, that daemon
     # does not yet exist, so we will get 503 Backend Not Ready,
     # unless we manually create it:
     scon, ccon = start_reactor(
         jm_single().config.get("DAEMON", "daemon_host"),
         jm_single().config.getint("DAEMON", "daemon_port"),
         None,
         daemon=True,
         rs=False)
     # must be manually set:
     self.scon = scon
     agent = get_nontor_agent()
     addr = self.get_route_root()
     addr += "/wallet/"
     addr += self.daemon.wallet_name
     addr += "/taker/coinjoin"
     addr = addr.encode()
     body = BytesProducer(
         json.dumps({
             "mixdepth": "1",
             "amount_sats": "22000000",
             "counterparties": "2",
             "destination": "2N2JD6wb56AfK4tfmM6PwdVmoYk2dCKf4Br"
         }).encode())
     yield self.do_request(agent, b"POST", addr, body,
                           self.process_do_coinjoin_response)
    def test_create_list_lock_unlock(self):
        """ A batch of tests in sequence here,
            so we can track the state of a created
            wallet and check it is what is expected.
            We test create first, so we have a wallet.

        1. create a wallet and have it persisted
           to disk in ./wallets, and get a token.
        2. lock that wallet.
        3. create a second wallet as above.
        4. list wallets and check they contain the new
           wallet.
        5. lock the existing wallet service, using the token.
        6. Unlock the original wallet with /unlock, get a token.
        7. Unlock the second wallet with /unlock, get a token.
        """
        # before starting, we have to shut down the existing
        # wallet service (usually this would be `lock`):
        self.daemon.services["wallet"] = None
        self.daemon.stopService()
        self.daemon.auth_disabled = False

        wfn1 = self.get_wallet_file_name(1)
        wfn2 = self.get_wallet_file_name(2)
        self.wfnames = [wfn1, wfn2]
        agent = get_nontor_agent()
        root = self.get_route_root()

        # 1. Create first
        addr = root + "/wallet/create"
        addr = addr.encode()
        body = BytesProducer(
            json.dumps({
                "walletname": wfn1,
                "password": "******",
                "wallettype": "sw-fb"
            }).encode())
        yield self.do_request(agent, b"POST", addr, body,
                              self.process_create_wallet_response)

        # 1a. Session request with valid token; should succeed
        yield self.do_session_request(agent,
                                      root,
                                      self.authorized_session_request_handler,
                                      token=self.jwt_token)
        # 1b. Session request without token, even though one is active; should succeed
        yield self.do_session_request(agent, root,
                                      self.authorized_session_request_handler)

        # 2. now *lock*
        addr = root + "/wallet/" + wfn1 + "/lock"
        addr = addr.encode()
        jlog.info("Using address: {}".format(addr))
        yield self.do_request(agent,
                              b"GET",
                              addr,
                              None,
                              self.process_lock_response,
                              token=self.jwt_token)

        # 2a. Session request with now invalid token; should fail
        yield self.do_session_request(
            agent,
            root,
            self.unauthorized_session_request_handler,
            token=self.jwt_token)
        # 2b. Session request without token, should still succeed.
        yield self.do_session_request(agent, root,
                                      self.authorized_session_request_handler)

        # 3. Create this secondary wallet (so we can test re-unlock)
        addr = root + "/wallet/create"
        addr = addr.encode()
        body = BytesProducer(
            json.dumps({
                "walletname": wfn2,
                "password": "******",
                "wallettype": "sw"
            }).encode())
        yield self.do_request(agent, b"POST", addr, body,
                              self.process_create_wallet_response)

        # 4. List wallets
        addr = root + "/wallet/all"
        addr = addr.encode()
        # does not require a token, though we just got one.
        yield self.do_request(agent, b"GET", addr, None,
                              self.process_list_wallets_response)

        # 5. now *lock* the active.
        addr = root + "/wallet/" + wfn2 + "/lock"
        addr = addr.encode()
        jlog.info("Using address: {}".format(addr))
        yield self.do_request(agent,
                              b"GET",
                              addr,
                              None,
                              self.process_lock_response,
                              token=self.jwt_token)
        # wallet service should now be stopped.
        # 6. Unlock the original wallet
        addr = root + "/wallet/" + wfn1 + "/unlock"
        addr = addr.encode()
        body = BytesProducer(json.dumps({"password": "******"}).encode())
        yield self.do_request(agent, b"POST", addr, body,
                              self.process_unlock_response)

        # 7. Unlock the second wallet again
        addr = root + "/wallet/" + wfn2 + "/unlock"
        addr = addr.encode()
        body = BytesProducer(json.dumps({"password": "******"}).encode())
        yield self.do_request(agent, b"POST", addr, body,
                              self.process_unlock_response)
def start_test_taker(wallet_service, i, num_ygs):
    # this rpc manager has auth disabled,
    # and the wallet_service is set manually,
    # so no unlock etc.
    mgr = TWalletRPCManager()
    mgr.daemon.services["wallet"] = wallet_service
    # because we are manually setting the wallet_service
    # of the JMWalletDaemon instance, we do not follow the
    # usual flow of `initialize_wallet_service`, we do not set
    # the auth token or start the websocket; so we must manually
    # sync the wallet, including bypassing any restart callback:
    def dummy_restart_callback(msg):
        log.warn("Ignoring rescan request from backend wallet service: " + msg)
    mgr.daemon.services["wallet"].add_restart_callback(dummy_restart_callback)
    mgr.daemon.wallet_name = wallet_name
    mgr.daemon.services["wallet"].startService()
    def get_client_factory():
        clientfactory = RegtestJMClientProtocolFactory(mgr.daemon.taker,
                                                       proto_type="TAKER")
        clientfactory.i = i
        clientfactory.set_directory_nodes(directory_node_indices)
        return clientfactory

    mgr.daemon.get_client_factory = get_client_factory
    # before preparing the RPC call to the wallet daemon,
    # we decide a coinjoin destination, counterparty count and amount.
    # Choosing a destination in the wallet is a bit easier because
    # we can query the mixdepth balance at the end.
    coinjoin_destination = mgr.daemon.services["wallet"].get_internal_addr(4)
    cj_amount = 22000000
    def n_cps_from_n_ygs(n):
        if n > 4:
            return n - 2
        if n > 2:
            return 2
        assert False, "Need at least 3 yield generators to test"
    n_cps = n_cps_from_n_ygs(num_ygs)
    # once the taker is finished we sanity check before
    # shutting down:
    def dummy_taker_finished(res, fromtx=False,
                               waittime=0.0, txdetails=None):
        jmprint("Taker is finished")
        # check that the funds have arrived.
        mbal = mgr.daemon.services["wallet"].get_balance_by_mixdepth()[4]
        assert mbal == cj_amount
        jmprint("Funds: {} sats successfully arrived into mixdepth 4.".format(cj_amount))
        stop_reactor()
    mgr.daemon.taker_finished = dummy_taker_finished
    mgr.start()
    agent = get_nontor_agent()
    addr = mgr.get_route_root()
    addr += "/wallet/"
    addr += mgr.daemon.wallet_name
    addr += "/taker/coinjoin"
    addr = addr.encode()
    body = BytesProducer(json.dumps({"mixdepth": "1",
        "amount_sats": cj_amount,
        "counterparties": str(n_cps),
        "destination": coinjoin_destination}).encode())
    yield mgr.do_request(agent, b"POST", addr, body,
                          process_coinjoin_response)