Beispiel #1
0
def test_session_topup(
        doggo_proxy,
        session: Session,
        http_doggo_url: str
):

    # Create a channel that has just enough capacity for one transfer.
    session.initial_deposit = lambda x: 0
    check_response(session.get(http_doggo_url))

    client = session.client
    open_channels = client.get_open_channels()
    assert len(open_channels) == 1
    channel1 = open_channels[0]
    assert channel1 == session.channel
    assert channel1.balance_sig
    assert channel1.balance == channel1.deposit

    # Do another payment. Topup should occur.
    check_response(session.get(http_doggo_url))
    open_channels = client.get_open_channels()
    assert len(open_channels) == 1
    channel2 = open_channels[0]
    assert channel2 == session.channel
    assert channel2.balance_sig
    assert channel2.balance < channel2.deposit
    assert channel1 == channel2
Beispiel #2
0
def test_session_topup(
        doggo_proxy,
        session: Session,
        http_doggo_url: str
):

    # Create a channel that has just enough capacity for one transfer.
    session.initial_deposit = lambda x: 0
    check_response(session.get(http_doggo_url))

    client = session.client
    open_channels = client.get_open_channels()
    assert len(open_channels) == 1
    channel1 = open_channels[0]
    assert channel1 == session.channel
    assert channel1.balance_sig
    assert channel1.balance == channel1.deposit

    # Do another payment. Topup should occur.
    check_response(session.get(http_doggo_url))
    open_channels = client.get_open_channels()
    assert len(open_channels) == 1
    channel2 = open_channels[0]
    assert channel2 == session.channel
    assert channel2.balance_sig
    assert channel2.balance < channel2.deposit
    assert channel1 == channel2
Beispiel #3
0
def test_cheating_client(
    doggo_proxy,
    web3,
    session: Session,
    wait_for_blocks,
    http_doggo_url: str,
):
    patch_on_http_response(session, abort_on=[502])
    balance = web3.eth.getBalance(doggo_proxy.channel_manager.receiver)
    assert balance > 0
    # remove all receiver's eth
    web3.eth.sendTransaction({
        'from': doggo_proxy.channel_manager.receiver,
        'to': FAUCET_ADDRESS,
        'value': balance - 90000
    })
    wait_for_blocks(1)
    session.get(http_doggo_url)
    # proxy is expected to return 502 - it has no funds
    assert session.last_response.status_code == 502
    web3.eth.sendTransaction({
        'from': FAUCET_ADDRESS,
        'to': doggo_proxy.channel_manager.receiver,
        'value': balance
    })
    wait_for_blocks(1)
    session.get(http_doggo_url)
    # now it should proceed normally
    assert session.last_response.status_code == 200
Beispiel #4
0
def test_ssl_client(
        doggo_proxy,
        session: Session,
        https_doggo_url: str
):
    with pytest.raises(SSLError):
        check_response(session.get(https_doggo_url))
    check_response(session.get(https_doggo_url, verify=False))
Beispiel #5
0
def test_ssl_client(
        doggo_proxy,
        session: Session,
        https_doggo_url: str
):
    with pytest.raises(SSLError):
        check_response(session.get(https_doggo_url))
    check_response(session.get(https_doggo_url, verify=False))
Beispiel #6
0
def test_status_codes(
        doggo_proxy,
        session: Session,
        http_doggo_url: str
):
    response = session.get(http_doggo_url)
    assert response.status_code == 200
    response = session.get(http_doggo_url[:-1])
    assert response.status_code == 404
Beispiel #7
0
def test_status_codes(
        doggo_proxy,
        session: Session,
        http_doggo_url: str
):
    response = session.get(http_doggo_url)
    assert response.status_code == 200
    response = session.get(http_doggo_url[:-1])
    assert response.status_code == 404
Beispiel #8
0
def test_cheating_client(
        doggo_proxy,
        session: Session,
        http_doggo_url: str
):
    """this test scenario where client sends less funds than what is requested
        by the server. In such case, a "RDN-Invalid-Amount=1" header should
        be sent in a server's reply
    """
    def patched_payment(
            self: Session,
            method: str,
            url: str,
            response: Response,
            **kwargs
    ):
        response.headers[HTTPHeaders.PRICE] = str(
            int(response.headers[HTTPHeaders.PRICE]) + self.price_adjust
        )
        return Session.on_payment_requested(self, method, url, response, **kwargs)

    def patched_on_invalid_amount(self, method: str, url: str, response: Response, **kwargs):
        self.invalid_amount_received += 1
        price = int(response.headers[HTTPHeaders.PRICE])
        Session.on_invalid_amount(self, method, url, response, **kwargs)
        # on_invalid_amount will already prepare the next payment which we don't execute anymore,
        # so revert that.
        self.channel.update_balance(self.channel.balance - price)
        return False

    session.on_invalid_amount = types.MethodType(
        patched_on_invalid_amount,
        session
    )
    session.on_payment_requested = types.MethodType(
        patched_payment,
        session
    )

    session.invalid_amount_received = 0

    # correct amount
    session.price_adjust = 0
    response = session.get(http_doggo_url)
    check_response(response)
    assert session.invalid_amount_received == 0
    # underpay
    session.price_adjust = -1
    response = session.get(http_doggo_url)
    assert response is None
    assert session.invalid_amount_received == 1
    # overpay
    session.price_adjust = 1
    response = session.get(http_doggo_url)
    assert response is None
    assert session.invalid_amount_received == 2
Beispiel #9
0
def test_cheating_client(
        doggo_proxy,
        session: Session,
        http_doggo_url: str
):
    """this test scenario where client sends less funds than what is requested
        by the server. In such case, a "RDN-Invalid-Amount=1" header should
        be sent in a server's reply
    """
    def patched_payment(
            self: Session,
            method: str,
            url: str,
            response: Response,
            **kwargs
    ):
        response.headers[HTTPHeaders.PRICE] = str(
            int(response.headers[HTTPHeaders.PRICE]) + self.price_adjust
        )
        return Session.on_payment_requested(self, method, url, response, **kwargs)

    def patched_on_invalid_amount(self, method: str, url: str, response: Response, **kwargs):
        self.invalid_amount_received += 1
        price = int(response.headers[HTTPHeaders.PRICE])
        Session.on_invalid_amount(self, method, url, response, **kwargs)
        # on_invalid_amount will already prepare the next payment which we don't execute anymore,
        # so revert that.
        self.channel.update_balance(self.channel.balance - price)
        return False

    session.on_invalid_amount = types.MethodType(
        patched_on_invalid_amount,
        session
    )
    session.on_payment_requested = types.MethodType(
        patched_payment,
        session
    )

    session.invalid_amount_received = 0

    # correct amount
    session.price_adjust = 0
    response = session.get(http_doggo_url)
    check_response(response)
    assert session.invalid_amount_received == 0
    # underpay
    session.price_adjust = -1
    response = session.get(http_doggo_url)
    assert response.status_code == 402
    assert session.invalid_amount_received == 1
    # overpay
    session.price_adjust = 1
    response = session.get(http_doggo_url)
    assert response.status_code == 402
    assert session.invalid_amount_received == 2
Beispiel #10
0
def test_status_codes(
        doggo_proxy,
        session: Session,
        http_doggo_url: str
):
    patch_on_http_response(session, abort_on=[404])
    session.get(http_doggo_url)
    assert session.last_response.status_code == 200
    session.get(http_doggo_url[:-1])
    assert session.last_response.status_code == 404
Beispiel #11
0
def close_channels(private_key: str,
                   password_path: str,
                   resource: str,
                   channel_manager_address: str = None,
                   web3: Web3 = None,
                   retry_interval: float = 5,
                   endpoint_url: str = 'http://0.0.0.0:5010',
                   close_channel: bool = False):

    # Create the client session.
    session = Session(endpoint_url=endpoint_url,
                      private_key=private_key,
                      key_password_path=password_path,
                      channel_manager_address=channel_manager_address,
                      web3=web3,
                      retry_interval=retry_interval,
                      close_channel_on_exit=close_channel)

    #conn = Client(monitor_address)
    #conn.send('share')
    ##print(conn.recv())
    #conn.close()

    print("Private Key:", private_key)
    addr = privkey_to_addr(private_key)
    print("Address:", addr)
    #    response = requests.get('http://0.0.0.0:5000/api/1/channels/{}'.format(addr))
    #response = session.get('{}/api/1/channels/{}'.format('http://0.0.0.0:5000', addr))
    #print(response)

    response = session.get('{}/{}'.format('http://0.0.0.0:5010', resource))
    print(response)
    print(response.text)
    print(response.content)
    print(response.headers)
    #
    time.sleep(4)

    response = session.get('{}/{}'.format('http://0.0.0.0:5010', resource))
    print(response)
    print(response.text)
    print(response.content)
    print(response.headers)

    time.sleep(4)

    response = session.get('{}/{}'.format('http://0.0.0.0:5010', resource))
    print(response)
    print(response.text)
    print(response.content)
    print(response.headers)

    #    time.sleep(10)

    session.channel.close(balance=session.channel.balance - 1)
Beispiel #12
0
def run(private_key: str,
        password_path: str,
        resource: str,
        channel_manager_address: str = None,
        web3: Web3 = None,
        retry_interval: float = 5,
        endpoint_url: str = 'http://localhost:5000'):
    # Create the client session.
    session = Session(endpoint_url=endpoint_url,
                      private_key=private_key,
                      key_password_path=password_path,
                      channel_manager_address=channel_manager_address,
                      web3=web3,
                      retry_interval=retry_interval)
    # Get the resource. If payment is required, client will attempt to create
    # a channel or will use existing one.
    response = session.get('{}/{}'.format(endpoint_url, resource))

    if response.status_code == requests.codes.OK:
        if re.match('^text/', response.headers['Content-Type']):
            logging.info("Got the resource {} type={}:\n{}".format(
                resource, response.headers.get('Content-Type', '???'),
                response.text))
        else:
            logging.info("Got the resource {} type={} (not echoed)".format(
                resource, response.headers.get('Content-Type', '???')))
    else:
        logging.error("Error getting the resource. Code={} body={}".format(
            response.status_code, response.text))
    return response
Beispiel #13
0
def test_session_existing_channel(doggo_proxy, session: Session,
                                  receiver_address: str, http_doggo_url: str):
    client = session.client
    channel = client.open_channel(receiver_address, 50)
    check_response(session.get(http_doggo_url))
    assert channel.balance == 2
    assert channel.deposit == 50
Beispiel #14
0
class ETHTickerClient(ttk.Frame):
    def __init__(
            self,
            sender_privkey: str,
            session: Session = None,
            poll_interval: float = 5
    ) -> None:
        self.poll_interval = poll_interval

        self.root = tkinter.Tk()
        ttk.Frame.__init__(self, self.root)
        self.root.title('µRaiden ETH Ticker')
        self.root.protocol('WM_DELETE_WINDOW', self.close)
        self.pack()
        self.pricevar = tkinter.StringVar(value='0.00 USD')
        ttk.Label(self, textvariable=self.pricevar, font=('Helvetica', '72')).pack()

        if session is None:
            self.session = Session(
                private_key=sender_privkey,
                close_channel_on_exit=True,
                endpoint_url='http://localhost:5000'
            )
        else:
            self.session = session

        self.active_query = False
        self.running = False

    def run(self):
        self.running = True
        self.root.after(0, self.query_price)
        self.root.mainloop()

    def query_price(self):
        if not self.running:
            return
        self.active_query = True

        response = self.session.get('http://localhost:5000/ETHUSD')
        if response:
            price = float(response.json()['last_price'])
            log.info('New price received: {:.2f} USD'.format(price))
            self.pricevar.set('{:.2f} USD'.format(price))
        else:
            log.warning('No response.')

        if self.running:
            self.root.after(int(self.poll_interval * 1000), self.query_price)
        self.active_query = False

    def close(self):
        log.info('Shutting down gracefully.')
        self.running = False
        self.root.destroy()
        # Sloppy handling of thread joining but works for this small demo.
        while self.active_query:
            gevent.sleep(1)

        self.session.close()
Beispiel #15
0
class ETHTickerClient(ttk.Frame):
    def __init__(
            self,
            sender_privkey: str,
            session: Session = None,
            poll_interval: float = 5
    ) -> None:
        self.poll_interval = poll_interval

        self.root = tkinter.Tk()
        ttk.Frame.__init__(self, self.root)
        self.root.title('µRaiden ETH Ticker')
        self.root.protocol('WM_DELETE_WINDOW', self.close)
        self.pack()
        self.pricevar = tkinter.StringVar(value='0.00 USD')
        ttk.Label(self, textvariable=self.pricevar, font=('Helvetica', '72')).pack()

        if session is None:
            self.session = Session(
                private_key=sender_privkey,
                close_channel_on_exit=True,
                endpoint_url='http://localhost:5000'
            )
        else:
            self.session = session

        self.active_query = False
        self.running = False

    def run(self):
        self.running = True
        self.root.after(0, self.query_price)
        self.root.mainloop()

    def query_price(self):
        if not self.running:
            return
        self.active_query = True

        response = self.session.get('http://localhost:5000/ETHUSD')
        if response:
            price = float(response.json()['last_price'])
            log.info('New price received: {:.2f} USD'.format(price))
            self.pricevar.set('{:.2f} USD'.format(price))
        else:
            log.warning('No response.')

        if self.running:
            self.root.after(int(self.poll_interval * 1000), self.query_price)
        self.active_query = False

    def close(self):
        log.info('Shutting down gracefully.')
        self.running = False
        self.root.destroy()
        # Sloppy handling of thread joining but works for this small demo.
        while self.active_query:
            gevent.sleep(1)

        self.session.close()
Beispiel #16
0
def test_full_cycle_error_500(session: Session, api_endpoint_address: str,
                              token_address: str, channel_manager_address: str,
                              receiver_address: str):
    session.initial_deposit = lambda x: x

    with requests_mock.mock() as server_mock:
        headers1 = Munch()
        headers1.token_address = token_address
        headers1.contract_address = channel_manager_address
        headers1.receiver_address = receiver_address
        headers1.price = '3'

        headers2 = Munch()
        headers2.cost = '3'

        headers1 = HTTPHeaders.serialize(headers1)
        headers2 = HTTPHeaders.serialize(headers2)

        url = 'http://{}/something'.format(api_endpoint_address)
        server_mock.get(url, [{
            'status_code': 402,
            'headers': headers1
        }, {
            'status_code': 500,
            'headers': {}
        }, {
            'status_code': 200,
            'headers': headers2,
            'text': 'success'
        }])
        response = session.get(url)

    # First cycle, request price.
    request = server_mock.request_history[0]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address

    # Second cycle, pay price but receive error.
    request = server_mock.request_history[1]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address
    assert request.headers['RDN-Balance'] == '3'

    assert session.channel.balance == 3
    balance_sig_hex = encode_hex(session.channel.balance_sig)
    assert request.headers['RDN-Balance-Signature'] == balance_sig_hex

    # Third cycle, retry naively.
    request = server_mock.request_history[2]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address
    assert request.headers['RDN-Balance'] == '3'
    assert session.channel.balance == 3
    assert request.headers['RDN-Balance-Signature'] == balance_sig_hex
    assert session.channel.balance_sig
    assert response.text == 'success'
Beispiel #17
0
def test_resource_request(doggo_proxy, http_doggo_url: str, session: Session):
    n_requests = 10
    session.initial_deposit = lambda x: (n_requests + 1) * x

    # First transfer creates channel on-chain => exclude from profiling.
    response = session.get(http_doggo_url)
    assert response.text == 'HI I AM A DOGGO'

    t_start = time.time()
    for i in range(n_requests):
        log.debug('Transfer {}'.format(i))
        response = session.get(http_doggo_url)
        assert response.text == 'HI I AM A DOGGO'
    t_diff = time.time() - t_start

    log.info("{} requests in {} ({} rps)".format(
        n_requests, datetime.timedelta(seconds=t_diff), n_requests / t_diff))
Beispiel #18
0
def test_cache_cleanup(empty_proxy: PaywalledProxy, usession: uSession,
                       api_endpoint_address: str):
    now = time.time()
    es_mock = ElasticsearchBackend(None)

    api_path = 'http://' + api_endpoint_address
    resource_url = '/some_index/some_type/_search'
    url = api_path + resource_url

    bodies = [
        {
            'query': 'query something'
        },
        {
            'query': 'query some other thing'
        },
        {
            'query': 'query some third thing'
        },
    ]
    requests = [
        Request.from_values(method='GET',
                            base_url=api_path,
                            path=resource_url,
                            content_type='application/json',
                            data=json.dumps(bodies[0])),
        Request.from_values(method='GET',
                            base_url=api_path,
                            path=resource_url,
                            content_type='application/json',
                            data=json.dumps(bodies[1])),
        Request.from_values(method='GET',
                            base_url=api_path,
                            path=resource_url,
                            content_type='application/json',
                            data=json.dumps(bodies[2]))
    ]
    resources = [
        Resource(content='success1', price=4, expires_at=now - 100),
        Resource(content='success2', price=4, expires_at=now + 100),
        Resource(content='success3', price=4, expires_at=now - 100),
    ]
    es_mock.search = mock.Mock(return_value=resources[1])

    server = APIServer(empty_proxy, es=es_mock)
    server.resource_cache.update({
        ExpensiveElasticsearch.get_request_key(requests[0]):
        resources[0],
        ExpensiveElasticsearch.get_request_key(requests[1]):
        resources[1],
        ExpensiveElasticsearch.get_request_key(requests[2]):
        resources[2]
    })
    assert len(server.resource_cache) == 3

    response = usession.get(url, json=bodies[1])
    assert response.json() == 'success2'
    assert len(server.resource_cache) == 1
Beispiel #19
0
def test_custom_headers(
        session: Session,
        api_endpoint_address: str,
        token_address: str,
        channel_manager_address: str,
        receiver_address: str
):
    session.initial_deposit = lambda x: x

    with requests_mock.mock(real_http=True) as server_mock:
        headers1 = Munch()
        headers1.token_address = token_address
        headers1.contract_address = channel_manager_address
        headers1.receiver_address = receiver_address
        headers1.price = '7'

        headers2 = Munch()
        headers2.cost = '7'

        headers1 = HTTPHeaders.serialize(headers1)
        headers2 = HTTPHeaders.serialize(headers2)

        url = 'http://{}/something'.format(api_endpoint_address)
        server_mock.get(url, [
            {'status_code': 402, 'headers': headers1},
            {'status_code': 200, 'headers': headers2, 'text': 'success'}
        ])
        response = session.get(url, headers={
            'someheader': 'somevalue',
            # This should override the actual balance but doesn't actually make sense.
            'RDN-Balance': '5'
        })

    # Filter out any requests made to the ethereum node.
    request_history = [request for request in server_mock.request_history if request.port == 5000]

    # First cycle, request price.
    request = request_history[0]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address
    assert request.headers['RDN-Balance'] == '5'
    assert request.headers['someheader'] == 'somevalue'

    # Second cycle, pay price.
    request = request_history[1]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address
    assert request.headers['RDN-Balance'] == '5'
    assert request.headers['someheader'] == 'somevalue'

    assert session.channel.balance == 7
    balance_sig_hex = encode_hex(session.channel.balance_sig)
    assert request.headers['RDN-Balance-Signature'] == balance_sig_hex
    assert session.channel.balance_sig
    assert response.text == 'success'
Beispiel #20
0
def test_custom_headers(
        session: Session,
        api_endpoint_address: str,
        token_address: str,
        channel_manager_address: str,
        receiver_address: str
):
    session.initial_deposit = lambda x: x

    with requests_mock.mock(real_http=True) as server_mock:
        headers1 = Munch()
        headers1.token_address = token_address
        headers1.contract_address = channel_manager_address
        headers1.receiver_address = receiver_address
        headers1.price = '7'

        headers2 = Munch()
        headers2.cost = '7'

        headers1 = HTTPHeaders.serialize(headers1)
        headers2 = HTTPHeaders.serialize(headers2)

        url = 'http://{}/something'.format(api_endpoint_address)
        server_mock.get(url, [
            {'status_code': 402, 'headers': headers1},
            {'status_code': 200, 'headers': headers2, 'text': 'success'}
        ])
        response = session.get(url, headers={
            'someheader': 'somevalue',
            # This should override the actual balance but doesn't actually make sense.
            'RDN-Balance': '5'
        })

    # Filter out any requests made to the ethereum node.
    request_history = [request for request in server_mock.request_history if request.port == 5000]

    # First cycle, request price.
    request = request_history[0]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address
    assert request.headers['RDN-Balance'] == '5'
    assert request.headers['someheader'] == 'somevalue'

    # Second cycle, pay price.
    request = request_history[1]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address
    assert request.headers['RDN-Balance'] == '5'
    assert request.headers['someheader'] == 'somevalue'

    assert session.channel.balance == 7
    balance_sig_hex = encode_hex(session.channel.balance_sig)
    assert request.headers['RDN-Balance-Signature'] == balance_sig_hex
    assert session.channel.balance_sig
    assert response.text == 'success'
Beispiel #21
0
def test_error_handling(session: Session, api_endpoint_address: str,
                        token_address: str, channel_manager_address: str,
                        receiver_address: str):
    nonexisting_channel_mock = mock.patch.object(
        session,
        'on_nonexisting_channel',
        wraps=session.on_nonexisting_channel).start()
    insufficient_confirmations_mock = mock.patch.object(
        session,
        'on_insufficient_confirmations',
        wraps=session.on_insufficient_confirmations).start()
    insufficient_funds_mock = mock.patch.object(
        session,
        'on_invalid_balance_proof',
        wraps=session.on_invalid_balance_proof).start()
    invalid_contract_address_mock = mock.patch.object(
        session,
        'on_invalid_contract_address',
        wraps=session.on_invalid_contract_address).start()

    with requests_mock.mock(real_http=True) as server_mock:
        headers = {
            HTTPHeaders.TOKEN_ADDRESS: token_address,
            HTTPHeaders.CONTRACT_ADDRESS: channel_manager_address,
            HTTPHeaders.RECEIVER_ADDRESS: receiver_address,
            HTTPHeaders.PRICE: '3'
        }
        headers = [headers.copy() for _ in range(5)]
        headers[1][HTTPHeaders.NONEXISTING_CHANNEL] = '1'
        headers[2][HTTPHeaders.INSUF_CONFS] = '1'
        headers[3][HTTPHeaders.INVALID_PROOF] = '1'
        headers[4][HTTPHeaders.CONTRACT_ADDRESS] = '0x' + '12' * 20

        url = 'http://{}/something'.format(api_endpoint_address)
        server_mock.get(url, [{
            'status_code': 402,
            'headers': headers[0]
        }, {
            'status_code': 402,
            'headers': headers[1]
        }, {
            'status_code': 402,
            'headers': headers[2]
        }, {
            'status_code': 402,
            'headers': headers[3]
        }, {
            'status_code': 402,
            'headers': headers[4]
        }])
        response = session.get(url)

    assert response.status_code == 402
    assert nonexisting_channel_mock.call_count == 1
    assert insufficient_confirmations_mock.call_count == 1
    assert insufficient_funds_mock.call_count == 1
    assert invalid_contract_address_mock.call_count == 1
def test_resource_request(doggo_proxy, http_doggo_url: str, session: Session):
    n_requests = 10
    session.initial_deposit = lambda x: (n_requests + 1) * x

    # First transfer creates channel on-chain => exclude from profiling.
    response = session.get(http_doggo_url)
    assert response.text == 'HI I AM A DOGGO'

    t_start = time.time()
    for i in range(n_requests):
        log.debug('Transfer {}'.format(i))
        response = session.get(http_doggo_url)
        assert response.text == 'HI I AM A DOGGO'
    t_diff = time.time() - t_start

    log.info("{} requests in {} ({} rps)".format(
        n_requests, datetime.timedelta(seconds=t_diff), n_requests / t_diff)
    )
Beispiel #23
0
def test_error_handling(
        session: Session,
        api_endpoint_address: str,
        token_address: str,
        channel_manager_address: str,
        receiver_address: str
):
    nonexisting_channel_mock = mock.patch.object(
        session,
        'on_nonexisting_channel',
        wraps=session.on_nonexisting_channel
    ).start()
    insufficient_confirmations_mock = mock.patch.object(
        session,
        'on_insufficient_confirmations',
        wraps=session.on_insufficient_confirmations
    ).start()
    insufficient_funds_mock = mock.patch.object(
        session,
        'on_invalid_balance_proof',
        wraps=session.on_invalid_balance_proof
    ).start()
    invalid_contract_address_mock = mock.patch.object(
        session,
        'on_invalid_contract_address',
        wraps=session.on_invalid_contract_address
    ).start()

    with requests_mock.mock(real_http=True) as server_mock:
        headers = {
            HTTPHeaders.TOKEN_ADDRESS: token_address,
            HTTPHeaders.CONTRACT_ADDRESS: channel_manager_address,
            HTTPHeaders.RECEIVER_ADDRESS: receiver_address,
            HTTPHeaders.PRICE: '3'
        }
        headers = [headers.copy() for _ in range(5)]
        headers[1][HTTPHeaders.NONEXISTING_CHANNEL] = '1'
        headers[2][HTTPHeaders.INSUF_CONFS] = '1'
        headers[3][HTTPHeaders.INVALID_PROOF] = '1'
        headers[4][HTTPHeaders.CONTRACT_ADDRESS] = '0x' + '12' * 20

        url = 'http://{}/something'.format(api_endpoint_address)
        server_mock.get(url, [
            {'status_code': 402, 'headers': headers[0]},
            {'status_code': 402, 'headers': headers[1]},
            {'status_code': 402, 'headers': headers[2]},
            {'status_code': 402, 'headers': headers[3]},
            {'status_code': 402, 'headers': headers[4]}
        ])
        response = session.get(url)

    assert response.status_code == 402
    assert nonexisting_channel_mock.call_count == 1
    assert insufficient_confirmations_mock.call_count == 1
    assert insufficient_funds_mock.call_count == 1
    assert invalid_contract_address_mock.call_count == 1
Beispiel #24
0
def test_session_close(
        doggo_proxy,
        session: Session,
        http_doggo_url: str
):
    client = session.client
    check_response(session.get(http_doggo_url))
    session.close_channel()
    open_channels = client.get_open_channels()
    assert len(open_channels) == 0
Beispiel #25
0
def test_session_close(
        doggo_proxy,
        session: Session,
        http_doggo_url: str
):
    client = session.client
    check_response(session.get(http_doggo_url))
    session.close_channel()
    open_channels = client.get_open_channels()
    assert len(open_channels) == 0
Beispiel #26
0
def test_session_existing_channel(
        doggo_proxy,
        session: Session,
        receiver_address: str,
        http_doggo_url: str
):
    client = session.client
    channel = client.open_channel(receiver_address, 50)
    check_response(session.get(http_doggo_url))
    assert channel.balance == 2
    assert channel.deposit == 50
Beispiel #27
0
def test_cheating_client(doggo_proxy, web3, session: Session,
                         wait_for_transaction, http_doggo_url: str,
                         faucet_private_key: str, faucet_address: str,
                         receiver_privkey: str, receiver_address: str):
    balance = web3.eth.getBalance(doggo_proxy.channel_manager.receiver)
    assert balance > 0
    # remove all receiver's eth
    tx = create_signed_transaction(receiver_privkey, web3, faucet_address,
                                   balance - GAS_PRICE * POT_GAS_LIMIT)
    tx_hash = web3.eth.sendRawTransaction(tx)
    wait_for_transaction(tx_hash)
    response = session.get(http_doggo_url)
    # proxy is expected to return 502 - it has no funds
    assert response.status_code == 502
    tx = create_signed_transaction(faucet_private_key, web3, receiver_address,
                                   balance - GAS_PRICE * POT_GAS_LIMIT)
    tx_hash = web3.eth.sendRawTransaction(tx)
    wait_for_transaction(tx_hash)
    response = session.get(http_doggo_url)
    # now it should proceed normally
    assert response.status_code == 200
Beispiel #28
0
def test_full_cycle_error_500(session: Session, api_endpoint_address: str,
                              token_address: str, channel_manager_address: str,
                              receiver_address: str):
    session.initial_deposit = lambda x: x

    with requests_mock.mock(real_http=True) as server_mock:
        headers1 = Munch()
        headers1.token_address = token_address
        headers1.contract_address = channel_manager_address
        headers1.receiver_address = receiver_address
        headers1.price = '3'

        headers2 = Munch()
        headers2.cost = '3'

        headers1 = HTTPHeaders.serialize(headers1)
        headers2 = HTTPHeaders.serialize(headers2)

        url = 'http://{}/something'.format(api_endpoint_address)
        server_mock.get(url, [{
            'status_code': 402,
            'headers': headers1
        }, {
            'status_code': 500,
            'headers': {}
        }])
        response = session.get(url)

    # Filter out any requests made to the ethereum node.
    request_history = [
        request for request in server_mock.request_history
        if request.port == 5000
    ]

    # First cycle, request price.
    request = request_history[0]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address

    # Second cycle, pay price but receive error.
    request = request_history[1]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address
    assert request.headers['RDN-Balance'] == '3'

    assert session.channel.balance == 3
    balance_sig_hex = encode_hex(session.channel.balance_sig)
    assert request.headers['RDN-Balance-Signature'] == balance_sig_hex
    assert response.status_code == 500
Beispiel #29
0
def test_session(doggo_proxy, session: Session, sender_address: str,
                 receiver_address: str, http_doggo_url: str):
    check_response(session.get(http_doggo_url))

    client = session.client
    open_channels = client.get_open_channels()
    assert len(open_channels) == 1

    channel = open_channels[0]
    assert channel == session.channel
    assert channel.balance_sig
    assert channel.balance < channel.deposit
    assert channel.sender == sender_address
    assert channel.receiver == receiver_address
Beispiel #30
0
def test_full_cycle_error_500(
        session: Session,
        api_endpoint_address: str,
        token_address: str,
        channel_manager_address: str,
        receiver_address: str
):
    session.initial_deposit = lambda x: x

    with requests_mock.mock(real_http=True) as server_mock:
        headers1 = Munch()
        headers1.token_address = token_address
        headers1.contract_address = channel_manager_address
        headers1.receiver_address = receiver_address
        headers1.price = '3'

        headers2 = Munch()
        headers2.cost = '3'

        headers1 = HTTPHeaders.serialize(headers1)
        headers2 = HTTPHeaders.serialize(headers2)

        url = 'http://{}/something'.format(api_endpoint_address)
        server_mock.get(url, [
            {'status_code': 402, 'headers': headers1},
            {'status_code': 500, 'headers': {}}
        ])
        response = session.get(url)

    # Filter out any requests made to the ethereum node.
    request_history = [request for request in server_mock.request_history if request.port == 5000]

    # First cycle, request price.
    request = request_history[0]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address

    # Second cycle, pay price but receive error.
    request = request_history[1]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address
    assert request.headers['RDN-Balance'] == '3'

    assert session.channel.balance == 3
    balance_sig_hex = encode_hex(session.channel.balance_sig)
    assert request.headers['RDN-Balance-Signature'] == balance_sig_hex
    assert response.status_code == 500
def test_cheating_client(
        doggo_proxy,
        web3,
        session: Session,
        wait_for_transaction,
        http_doggo_url: str,
        faucet_private_key: str,
        faucet_address: str,
        receiver_privkey: str,
        receiver_address: str
):
    balance = web3.eth.getBalance(doggo_proxy.channel_manager.receiver)
    assert balance > 0
    # remove all receiver's eth
    tx = create_signed_transaction(
        receiver_privkey,
        web3,
        faucet_address,
        balance - NETWORK_CFG.GAS_PRICE * NETWORK_CFG.POT_GAS_LIMIT
    )
    tx_hash = web3.eth.sendRawTransaction(tx)
    wait_for_transaction(tx_hash)
    response = session.get(http_doggo_url)
    # proxy is expected to return 502 - it has no funds
    assert response.status_code == 502
    tx = create_signed_transaction(
        faucet_private_key,
        web3,
        receiver_address,
        balance - NETWORK_CFG.GAS_PRICE * NETWORK_CFG.POT_GAS_LIMIT
    )
    tx_hash = web3.eth.sendRawTransaction(tx)
    wait_for_transaction(tx_hash)
    response = session.get(http_doggo_url)
    # now it should proceed normally
    assert response.status_code == 200
Beispiel #32
0
def run(private_key: str,
        password_path: str,
        channel_manager_address: str = None,
        reqs: int = 20,
        web3: Web3 = None,
        retry_interval: float = 5,
        endpoint_url: str = 'http://localhost:5000'):
    # Create the client session.
    global session
    session = Session(endpoint_url=endpoint_url,
                      private_key=private_key,
                      key_password_path=password_path,
                      channel_manager_address=channel_manager_address,
                      web3=web3,
                      initial_deposit=lambda price: 10 * 1000 * 1000 * price,
                      topup_deposit=lambda price: 10 * 1000 * 1000 * price,
                      close_channel_on_exit=True,
                      retry_interval=retry_interval)
    resource = "/test/1"
    # Get the resource. If payment is required, client will attempt to create
    # a channel or will use existing one.
    last_time = time.time()
    global rqs
    last_reqs = 0
    for i in range(0, reqs):
        response = session.get('{}/{}'.format(endpoint_url, resource))

        if response.status_code == requests.codes.OK:
            rqs = rqs + 1
            t = time.time()
            if (t - last_time) >= 1:
                print("transaction rate: ", rqs - last_reqs, " req/sec")
                last_time = t
                last_reqs = rqs
            continue
            if re.match('^text/', response.headers['Content-Type']):
                logging.info("Got the resource {} type={}:\n{}".format(
                    resource, response.headers.get('Content-Type', '???'),
                    response.text))
            else:
                logging.info("Got the resource {} type={} (not echoed)".format(
                    resource, response.headers.get('Content-Type', '???')))
        else:
            logging.error("Error getting the resource. Code={} body={}".format(
                response.status_code, response.text))
    print(rqs, " requests processed, closing session.")
    session.close()
    return response
Beispiel #33
0
def run(
        private_key: str,
        password_path: str,
        resource: str,
        channel_manager_address: str = None,
        web3: Web3 = None,
        retry_interval: float = 5,
        endpoint_url: str = 'http://localhost:5000'
):
    # Create the client session.
    session = Session(
        endpoint_url=endpoint_url,
        private_key=private_key,
        key_password_path=password_path,
        channel_manager_address=channel_manager_address,
        web3=web3,
        retry_interval=retry_interval
    )
    # Get the resource. If payment is required, client will attempt to create
    # a channel or will use existing one.
    response = session.get('{}/{}'.format(endpoint_url, resource))

    if response.status_code == requests.codes.OK:
        if re.match('^text/', response.headers['Content-Type']):
            logging.info(
                "Got the resource {} type={}:\n{}".format(
                    resource,
                    response.headers.get('Content-Type', '???'),
                    response.text
                )
            )
        else:
            logging.info(
                "Got the resource {} type={} (not echoed)".format(
                    resource,
                    response.headers.get('Content-Type', '???')
                )
            )
    else:
        logging.error(
            "Error getting the resource. Code={} body={}".format(
                response.status_code,
                response.text
            )
        )
    return response
Beispiel #34
0
def test_session(
        doggo_proxy,
        session: Session,
        sender_address: str,
        receiver_address: str,
        http_doggo_url: str
):
    check_response(session.get(http_doggo_url))

    client = session.client
    open_channels = client.get_open_channels()
    assert len(open_channels) == 1

    channel = open_channels[0]
    assert channel == session.channel
    assert channel.balance_sig
    assert channel.balance < channel.deposit
    assert is_same_address(channel.sender, sender_address)
    assert is_same_address(channel.receiver, receiver_address)
Beispiel #35
0
def test_coop_close(doggo_proxy, session: Session, http_doggo_url: str):
    check_response(session.get(http_doggo_url))

    client = session.client
    open_channels = client.get_open_channels()
    assert len(open_channels) == 1

    channel = open_channels[0]
    import requests
    reply = requests.get('http://localhost:5000/api/1/channels/%s/%s' %
                         (channel.sender, channel.block))
    assert reply.status_code == 200
    json_reply = json.loads(reply.text)

    request_data = {'balance': json_reply['balance']}
    reply = requests.delete('http://localhost:5000/api/1/channels/%s/%s' %
                            (channel.sender, channel.block),
                            data=request_data)

    assert reply.status_code == 200
Beispiel #36
0
def test_cooperative_close_denied(session: Session, api_endpoint_address: str,
                                  token_address: str,
                                  channel_manager_address: str,
                                  receiver_address: str):
    cooperative_close_denied_mock = mock.patch.object(
        session,
        'on_cooperative_close_denied',
        wraps=session.on_cooperative_close_denied).start()

    with requests_mock.mock() as server_mock:
        headers = {
            HTTPHeaders.TOKEN_ADDRESS: token_address,
            HTTPHeaders.CONTRACT_ADDRESS: channel_manager_address,
            HTTPHeaders.RECEIVER_ADDRESS: receiver_address,
            HTTPHeaders.PRICE: '3'
        }
        headers = [headers.copy() for _ in range(2)]
        headers[1][HTTPHeaders.COST] = '3'

        url = 'http://{}/something'.format(api_endpoint_address)
        server_mock.get(url, [
            {
                'status_code': 402,
                'headers': headers[0]
            },
            {
                'status_code': 200,
                'headers': headers[1],
                'text': 'success'
            },
        ])
        channel_url = re.compile(
            'http://{}/api/1/channels/0x.{{40}}/\d+'.format(
                api_endpoint_address))
        server_mock.delete(channel_url, [{'status_code': 403}])
        response = session.get(url)
        session.close_channel()

    assert response.text == 'success'
    assert cooperative_close_denied_mock.call_count == 1
    assert session.client.channels[0].state == Channel.State.settling
Beispiel #37
0
def test_cooperative_close_denied(
        session: Session,
        api_endpoint_address: str,
        token_address: str,
        channel_manager_address: str,
        receiver_address: str
):
    cooperative_close_denied_mock = mock.patch.object(
        session,
        'on_cooperative_close_denied',
        wraps=session.on_cooperative_close_denied
    ).start()

    with requests_mock.mock(real_http=True) as server_mock:
        headers = {
            HTTPHeaders.TOKEN_ADDRESS: token_address,
            HTTPHeaders.CONTRACT_ADDRESS: channel_manager_address,
            HTTPHeaders.RECEIVER_ADDRESS: receiver_address,
            HTTPHeaders.PRICE: '3'
        }
        headers = [headers.copy() for _ in range(2)]
        headers[1][HTTPHeaders.COST] = '3'

        url = 'http://{}/something'.format(api_endpoint_address)
        server_mock.get(url, [
            {'status_code': 402, 'headers': headers[0]},
            {'status_code': 200, 'headers': headers[1], 'text': 'success'},
        ])
        channel_url = re.compile(
            'http://{}/api/1/channels/0x.{{40}}/\d+'.format(api_endpoint_address)
        )
        server_mock.delete(channel_url, [
            {'status_code': 403}
        ])
        response = session.get(url)
        session.close_channel()

    assert response.text == 'success'
    assert cooperative_close_denied_mock.call_count == 1
    assert session.channel.state == Channel.State.settling
Beispiel #38
0
def test_coop_close(
        doggo_proxy,
        session: Session,
        http_doggo_url: str
):
    check_response(session.get(http_doggo_url))

    client = session.client
    open_channels = client.get_open_channels()
    assert len(open_channels) == 1

    channel = open_channels[0]
    import requests
    reply = requests.get('http://localhost:5000/api/1/channels/%s/%s' %
                         (channel.sender, channel.block))
    assert reply.status_code == 200
    json_reply = json.loads(reply.text)

    request_data = {'balance': json_reply['balance']}
    reply = requests.delete('http://localhost:5000/api/1/channels/%s/%s' %
                            (channel.sender, channel.block), data=request_data)

    assert reply.status_code == 200
def run(private_key: str,
        password_path: str,
        resource: str,
        channel_manager_address: str = None,
        web3: Web3 = None,
        retry_interval: float = 5,
        endpoint_url: str = 'http://localhost:5000'):
    session = Session(endpoint_url=endpoint_url,
                      private_key=private_key,
                      key_password_path=password_path,
                      channel_manager_address=channel_manager_address,
                      web3=web3,
                      retry_interval=retry_interval,
                      initial_deposit=lambda x: x)
    stream_url = '{}/{}'.format(endpoint_url, resource)
    logging.info("Calling={}".format(stream_url))
    with session.get(stream_url, stream=True) as response:
        if response.status_code == requests.codes.OK:
            for line in response.iter_lines(decode_unicode=True):
                if line:
                    print(line)
        else:
            logging.error("Error getting the resource. Code={} body={}".format(
                response.status_code, response.text))
Beispiel #40
0
def test_full_cycle_adapt_balance(
        session: Session,
        api_endpoint_address: str,
        token_address: str,
        channel_manager_address: str,
        receiver_address: str
):
    # Simulate a lost balance signature.
    client = session.client
    channel = client.get_suitable_channel(receiver_address, 10, initial_deposit=lambda x: 2 * x)
    channel.create_transfer(3)
    lost_balance_sig = channel.balance_sig
    channel.update_balance(0)

    with requests_mock.mock() as server_mock:
        headers1 = Munch()
        headers1.token_address = token_address
        headers1.contract_address = channel_manager_address
        headers1.receiver_address = receiver_address
        headers1.price = '7'

        headers2 = headers1.copy()
        headers2.invalid_amount = '1'
        headers2.sender_balance = '3'
        headers2.balance_signature = encode_hex(lost_balance_sig)

        headers3 = Munch()
        headers3.cost = '7'

        headers1 = HTTPHeaders.serialize(headers1)
        headers2 = HTTPHeaders.serialize(headers2)
        headers3 = HTTPHeaders.serialize(headers3)

        url = 'http://{}/something'.format(api_endpoint_address)
        server_mock.get(url, [
            {'status_code': 402, 'headers': headers1},
            {'status_code': 402, 'headers': headers2},
            {'status_code': 200, 'headers': headers3, 'text': 'success'}
        ])

        response = session.get(url)

    # First cycle, request price.
    request = server_mock.request_history[0]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address

    # Second cycle, pay price based on outdated balance.
    request = server_mock.request_history[1]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address
    assert request.headers['RDN-Balance'] == '7'
    assert request.headers['RDN-Balance-Signature']

    # Third cycle, adapt new balance and pay price again.
    request = server_mock.request_history[2]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address
    assert request.headers['RDN-Balance'] == '10'

    assert session.channel.balance == 10
    balance_sig_hex = encode_hex(session.channel.balance_sig)
    assert request.headers['RDN-Balance-Signature'] == balance_sig_hex
    assert session.channel.balance_sig
    assert response.text == 'success'
Beispiel #41
0
def run(
        private_key: str,
        password_path: str,
        command: str,
        rpc_provider: str,
        channel_manager_address: str = None,
        web3: Web3 = None,
        retry_interval: float = 5,
        endpoint_url: str = 'http://localhost:5000'
):
    if channel_manager_address is None:
        web3 = Web3(HTTPProvider(rpc_provider))
        NETWORK_CFG.set_defaults(int(web3.version.network))

    # Create the client session.
    client = NewClient(
        private_key,
        password_path,
        NETWORK_CFG.CHANNEL_MANAGER_ADDRESS,
        web3
    )

    session = Session(
        client=client,
        endpoint_url=endpoint_url,
        private_key=private_key,
        key_password_path=password_path,
        channel_manager_address=NETWORK_CFG.CHANNEL_MANAGER_ADDRESS,
        web3=web3,
        retry_interval=retry_interval,
        initial_deposit= lambda price: 5 * TKN_DECIMALS,
        topup_deposit= lambda price: 5 * TKN_DECIMALS,
        close_channel_on_exit=False
    )
    # Get the resource. If payment is required, client will attempt to create
    # a channel or will use existing one.
    resource = command
    response = session.get('{}/{}'.format(endpoint_url, resource))

    if response.status_code == requests.codes.OK:
        if re.match('^text/', response.headers['Content-Type']):
            logging.info(
                "Got the resource {} type={}:\n{}".format(
                    resource,
                    response.headers.get('Content-Type', '???'),
                    response.text
                )
            )
        else:
            logging.info(
                "Got the resource {} type={} (not echoed)".format(
                    resource,
                    response.headers.get('Content-Type', '???')
                )
            )
    else:
        logging.error(
            "Error getting the resource. Code={} body={}".format(
                response.status_code,
                response.text
            )
        )
    return response
Beispiel #42
0
def test_full_cycle_adapt_balance(
        session: Session,
        api_endpoint_address: str,
        token_address: str,
        channel_manager_address: str,
        receiver_address: str
):
    # Simulate a lost balance signature.
    client = session.client
    channel = client.get_suitable_channel(receiver_address, 10, initial_deposit=lambda x: 2 * x)
    channel.create_transfer(3)
    lost_balance_sig = channel.balance_sig
    channel.update_balance(0)

    with requests_mock.mock(real_http=True) as server_mock:
        headers1 = Munch()
        headers1.token_address = token_address
        headers1.contract_address = channel_manager_address
        headers1.receiver_address = receiver_address
        headers1.price = '7'

        headers2 = headers1.copy()
        headers2.invalid_amount = '1'
        headers2.sender_balance = '3'
        headers2.balance_signature = encode_hex(lost_balance_sig)

        headers3 = Munch()
        headers3.cost = '7'

        headers1 = HTTPHeaders.serialize(headers1)
        headers2 = HTTPHeaders.serialize(headers2)
        headers3 = HTTPHeaders.serialize(headers3)

        url = 'http://{}/something'.format(api_endpoint_address)
        server_mock.get(url, [
            {'status_code': 402, 'headers': headers1},
            {'status_code': 402, 'headers': headers2},
            {'status_code': 200, 'headers': headers3, 'text': 'success'}
        ])

        response = session.get(url)

    # Filter out any requests made to the ethereum node.
    request_history = [request for request in server_mock.request_history if request.port == 5000]

    # First cycle, request price.
    request = request_history[0]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address

    # Second cycle, pay price based on outdated balance.
    request = request_history[1]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address
    assert request.headers['RDN-Balance'] == '7'
    assert request.headers['RDN-Balance-Signature']

    # Third cycle, adapt new balance and pay price again.
    request = request_history[2]
    assert request.path == '/something'
    assert request.method == 'GET'
    assert request.headers['RDN-Contract-Address'] == channel_manager_address
    assert request.headers['RDN-Balance'] == '10'

    assert session.channel.balance == 10
    balance_sig_hex = encode_hex(session.channel.balance_sig)
    assert request.headers['RDN-Balance-Signature'] == balance_sig_hex
    assert session.channel.balance_sig
    assert response.text == 'success'