Example #1
0
    def f():
        contract_address = get_random_address()
        channel_identifier = get_random_identifier()

        balance_hash_data = '%d' % random.randint(0, UINT64_MAX)
        additional_hash_data = '%d' % random.randint(0, UINT64_MAX)

        balance_hash = encode_hex((balance_hash_data.encode()))
        nonce = random.randint(0, UINT64_MAX)
        additional_hash = encode_hex(keccak(additional_hash_data.encode()))
        chain_id = 1

        privkey = get_random_privkey()
        privkey_non_closing = get_random_privkey()

        bp = HashedBalanceProof(  # type: ignore
            channel_identifier=channel_identifier,
            token_network_address=contract_address,
            chain_id=chain_id,
            balance_hash=balance_hash,
            nonce=nonce,
            additional_hash=additional_hash,
            priv_key=privkey,
        )
        monitor_request = UnsignedMonitorRequest.from_balance_proof(
            bp, reward_amount=TokenAmount(0)).sign(privkey_non_closing)
        return monitor_request, privkey, privkey_non_closing
Example #2
0
    def f(
        chain_id: ChainID = ChainID(1),
        amount: TokenAmount = TokenAmount(50),
        nonce: Nonce = Nonce(1),
    ) -> RequestMonitoring:
        balance_proof = HashedBalanceProof(
            channel_identifier=ChannelID(1),
            token_network_address=TokenNetworkAddress(b"1" * 20),
            chain_id=chain_id,
            nonce=nonce,
            additional_hash="",
            balance_hash=encode_hex(bytes([amount])),
            priv_key=get_random_privkey(),
        )
        request_monitoring = balance_proof.get_request_monitoring(
            privkey=non_closing_privkey,
            reward_amount=TokenAmount(55),
            monitoring_service_contract_address=Address(bytes([11] * 20)),
        )

        # usually not a property of RequestMonitoring, but added for convenience in these tests
        request_monitoring.non_closing_signer = to_checksum_address(  # type: ignore
            non_closing_address
        )
        return request_monitoring
Example #3
0
def test_get_iou(api_sut: PFSApi, api_url: str, token_network_model: TokenNetwork, make_iou):
    privkey = PrivateKey(get_random_privkey())
    sender = private_key_to_address(privkey)
    url = api_url + f"/v1/{to_checksum_address(token_network_model.address)}/payment/iou"

    def make_params(timestamp: str):
        params = {
            "sender": to_checksum_address(sender),
            "receiver": to_checksum_address(api_sut.pathfinding_service.address),
            "timestamp": timestamp,
        }
        local_signer = LocalSigner(private_key=privkey)
        params["signature"] = encode_hex(
            local_signer.sign(
                to_canonical_address(params["sender"])
                + to_canonical_address(params["receiver"])
                + params["timestamp"].encode("utf8")
            )
        )
        return params

    # Request without IOU in database
    params = make_params(datetime.utcnow().isoformat())
    response = requests.get(url, params=params)
    assert response.status_code == 404, response.json()
    assert response.json() == {"last_iou": None}

    # Add IOU to database
    iou = make_iou(
        privkey, api_sut.pathfinding_service.address, one_to_n_address=api_sut.one_to_n_address
    )
    iou.claimed = False
    api_sut.pathfinding_service.database.upsert_iou(iou)

    # Is returned IOU the one save into the db?
    response = requests.get(url, params=params)
    assert response.status_code == 200, response.json()
    iou_dict = IOU.Schema(exclude=["claimed"]).dump(iou)
    assert response.json()["last_iou"] == iou_dict

    # Invalid signatures must fail
    params["signature"] = encode_hex((int(params["signature"], 16) + 1).to_bytes(65, "big"))
    response = requests.get(url, params=params)
    assert response.status_code == 400, response.json()
    assert response.json()["error_code"] == exceptions.InvalidSignature.error_code

    # Timestamp must no be too old to prevent replay attacks
    old_timestamp = datetime.utcnow() - timedelta(days=1)
    params = make_params(old_timestamp.isoformat())
    response = requests.get(url, params=params)
    assert response.status_code == 400, response.json()
    assert response.json()["error_code"] == exceptions.RequestOutdated.error_code

    # Timestamp with timezone info is invalid
    for timestamp in (datetime.now(tz=timezone.utc).isoformat(), "2019-11-07T12:52:25.079Z"):
        params = make_params(timestamp)
        response = requests.get(url, params=params)
        assert response.status_code == 400, response.json()
        assert response.json()["error_code"] == exceptions.InvalidRequest.error_code
Example #4
0
def test_load_and_save_iou(pathfinding_service_mocked_listeners):
    pfs = pathfinding_service_mocked_listeners
    iou_dict = make_iou(get_random_privkey(), pfs.address)
    iou = IOU.Schema().load(iou_dict)[0]
    iou.claimed = False
    pfs.database.upsert_iou(iou)
    stored_iou = pfs.database.get_iou(iou.sender, iou.expiration_block)
    assert stored_iou == iou
Example #5
0
 def f():
     pk = get_random_privkey()
     ethereum_tester.add_account(pk)
     c = MockRaidenNode(pk, token_network, custom_token)
     c.client_registry = client_registry
     client_registry[c.address] = c
     send_funds(c.address)
     return c
Example #6
0
def test_get_iou(api_sut: ServiceApi, api_url: str,
                 token_network_model: TokenNetwork, make_iou):
    privkey = get_random_privkey()
    sender = private_key_to_address(privkey)
    url = api_url + f"/{to_checksum_address(token_network_model.address)}/payment/iou"

    def make_params(timestamp: datetime):
        params = {
            "sender": to_checksum_address(sender),
            "receiver":
            to_checksum_address(api_sut.pathfinding_service.address),
            "timestamp": timestamp.isoformat(),
        }
        local_signer = LocalSigner(private_key=decode_hex(privkey))
        params["signature"] = encode_hex(
            local_signer.sign(
                pack_data(
                    (params["sender"], "address"),
                    (params["receiver"], "address"),
                    (params["timestamp"], "string"),
                )))
        return params

    # Request without IOU in database
    params = make_params(datetime.utcnow())
    response = requests.get(url, params=params)
    assert response.status_code == 404, response.json()
    assert response.json() == {"last_iou": None}

    # Add IOU to database
    iou = make_iou(privkey,
                   api_sut.pathfinding_service.address,
                   one_to_n_address=api_sut.one_to_n_address)
    iou.claimed = False
    api_sut.pathfinding_service.database.upsert_iou(iou)

    # Is returned IOU the one save into the db?
    response = requests.get(url, params=params)
    assert response.status_code == 200, response.json()
    iou_dict = IOU.Schema(exclude=["claimed"]).dump(iou)
    assert response.json()["last_iou"] == iou_dict

    # Invalid signatures must fail
    params["signature"] = encode_hex(
        (int(params["signature"], 16) + 1).to_bytes(65, "big"))
    response = requests.get(url, params=params)
    assert response.status_code == 400, response.json()
    assert response.json(
    )["error_code"] == exceptions.InvalidSignature.error_code

    # Timestamp must no be too old to prevent replay attacks
    params = make_params(datetime.utcnow() - timedelta(days=1))
    response = requests.get(url, params=params)
    assert response.status_code == 400, response.json()
    assert response.json(
    )["error_code"] == exceptions.RequestOutdated.error_code
Example #7
0
def test_mr_with_unknown_signatures(context: Context,):
    """ The signatures are valid but don't belong to the participants.
    """
    context = setup_state_with_closed_channel(context)

    def assert_mr_is_ignored(mr):
        context.db.upsert_monitor_request(mr)

        event = ActionMonitoringTriggeredEvent(
            token_network_address=DEFAULT_TOKEN_NETWORK_ADDRESS,
            channel_identifier=DEFAULT_CHANNEL_IDENTIFIER,
            non_closing_participant=DEFAULT_PARTICIPANT2,
        )

        action_monitoring_triggered_event_handler(event, context)
        assert not context.monitoring_service_contract.functions.monitor.called

    assert_mr_is_ignored(get_signed_monitor_request(closing_privkey=get_random_privkey()))
    assert_mr_is_ignored(get_signed_monitor_request(nonclosing_privkey=get_random_privkey()))
Example #8
0
def test_get_iou(
    api_sut: ServiceApi, api_url: str, pathfinding_service_mock, token_network_model: TokenNetwork
):
    privkey = get_random_privkey()
    sender = private_key_to_address(privkey)
    url = api_url + f'/{token_network_model.address}/payment/iou'

    def make_params(timestamp: datetime):
        params = {
            'sender': sender,
            'receiver': api_sut.pathfinding_service.address,
            'timestamp': timestamp.isoformat(),
        }
        local_signer = LocalSigner(private_key=decode_hex(privkey))
        params['signature'] = encode_hex(
            local_signer.sign(
                pack_data(
                    ['address', 'address', 'string'],
                    [params['sender'], params['receiver'], params['timestamp']],
                )
            )
        )
        return params

    # Request without IOU in database
    params = make_params(datetime.utcnow())
    response = requests.get(url, params=params)
    assert response.status_code == 404, response.json()
    assert response.json() == {'last_iou': None}

    # Add IOU to database
    iou = make_iou(privkey, api_sut.pathfinding_service.address)
    iou.claimed = False
    api_sut.pathfinding_service.database.upsert_iou(iou)

    # Is returned IOU the one save into the db?
    response = requests.get(url, params=params)
    assert response.status_code == 200, response.json()
    iou_dict = IOU.Schema(exclude=['claimed']).dump(iou)[0]
    assert response.json()['last_iou'] == iou_dict

    # Invalid signatures must fail
    params['signature'] = encode_hex((int(params['signature'], 16) + 1).to_bytes(65, 'big'))
    response = requests.get(url, params=params)
    assert response.status_code == 400, response.json()
    assert response.json()['error_code'] == exceptions.InvalidSignature.error_code

    # Timestamp must no be too old to prevent replay attacks
    params = make_params(datetime.utcnow() - timedelta(days=1))
    response = requests.get(url, params=params)
    assert response.status_code == 400, response.json()
    assert response.json()['error_code'] == exceptions.RequestOutdated.error_code

    # kill all running greenlets
    gevent.killall([obj for obj in gc.get_objects() if isinstance(obj, gevent.Greenlet)])
Example #9
0
def build_request_monitoring():
    signer = LocalSigner(decode_hex(get_random_privkey()))
    non_closing_signer = LocalSigner(decode_hex(get_random_privkey()))

    def f(amount=1, nonce=1):
        balance_proof = make_balance_proof(signer=signer,
                                           amount=amount,
                                           nonce=nonce)
        partner_signed_balance_proof = SignedBlindedBalanceProof.from_balance_proof_signed_state(
            balance_proof, )
        request_monitoring = RequestMonitoring(
            onchain_balance_proof=partner_signed_balance_proof,
            reward_amount=55,
        )
        request_monitoring.sign(non_closing_signer)
        request_monitoring.non_closing_signer = to_checksum_address(
            non_closing_signer.address)
        return request_monitoring

    return f
Example #10
0
def build_request_monitoring():
    signer = LocalSigner(decode_hex(get_random_privkey()))
    non_closing_signer = LocalSigner(decode_hex(get_random_privkey()))

    def f(chain_id=1, **kwargs):
        balance_proof = make_balance_proof(signer=signer, **kwargs)
        balance_proof.chain_id = chain_id
        partner_signed_balance_proof = SignedBlindedBalanceProof.from_balance_proof_signed_state(
            balance_proof)
        request_monitoring = RequestMonitoring(
            onchain_balance_proof=partner_signed_balance_proof,
            reward_amount=TokenAmount(55))
        request_monitoring.sign(non_closing_signer)

        # usually not a property of RequestMonitoring, but added for convenience in these tests
        request_monitoring.non_closing_signer = to_checksum_address(  # type: ignore
            non_closing_signer.address)
        return request_monitoring

    return f
Example #11
0
def test_payment_with_new_iou_rejected(  # pylint: disable=too-many-locals
    api_sut,
    api_url: str,
    addresses: List[Address],
    token_network_model: TokenNetwork,
    make_iou: Callable,
):
    """ Regression test for https://github.com/raiden-network/raiden-services/issues/624 """

    initiator_address = to_checksum_address(addresses[0])
    target_address = to_checksum_address(addresses[1])
    url = api_url + "/" + to_checksum_address(
        token_network_model.address) + "/paths"
    default_params = {
        "from": initiator_address,
        "to": target_address,
        "value": 5,
        "max_paths": 3
    }

    def request_path_with(status_code=400, **kwargs):
        params = default_params.copy()
        params.update(kwargs)
        response = requests.post(url, json=params)
        assert response.status_code == status_code, response.json()
        return response

    # test with payment
    api_sut.service_fee = 100
    sender = get_random_privkey()
    iou = make_iou(
        sender,
        api_sut.pathfinding_service.address,
        one_to_n_address=api_sut.one_to_n_address,
        amount=100,
        expiration_block=1_234_567,
    )
    first_iou_dict = iou.Schema().dump(iou)
    second_iou = make_iou(
        sender,
        api_sut.pathfinding_service.address,
        one_to_n_address=api_sut.one_to_n_address,
        amount=200,
        expiration_block=1_234_568,
    )
    second_iou_dict = second_iou.Schema().dump(second_iou)

    response = request_path_with(status_code=200, iou=first_iou_dict)
    assert response.status_code == 200

    response = request_path_with(iou=second_iou_dict)
    assert response.json()["error_code"] == exceptions.UseThisIOU.error_code
Example #12
0
 def get():
     privkey = get_random_privkey()
     address = private_key_to_address(privkey)
     ethereum_tester.add_account(privkey)
     for faucet in web3.eth.accounts[:10]:
         try:
             web3.eth.sendTransaction({
                 'from': faucet,
                 'to': address,
                 'value': 1 * denoms.finney,  # pylint: disable=E1101
             })
             break
         except TransactionFailed:
             continue
     return address
Example #13
0
def test_deploy_script_token(
        web3,
):
    """ Run test token deployment function used in the deployment script

    This checks if deploy_token_contract() works correctly in the happy case,
    to make sure no code dependencies have been changed, affecting the deployment script.
    This does not check however that the cli command works correctly.
    """
    # normal deployment
    token_type = 'CustomToken'
    gas_limit = 5860000
    deployer = ContractDeployer(
        web3=web3,
        private_key=FAUCET_PRIVATE_KEY,
        gas_limit=gas_limit,
        gas_price=1,
        wait=10,
    )

    deployed_token = deployer.deploy_token_contract(
        token_supply=10000000,
        token_decimals=18,
        token_name='TestToken',
        token_symbol='TTT',
        token_type=token_type,
    )

    assert deployed_token[token_type] is not None
    assert isinstance(deployed_token[token_type], T_Address)

    # check that it fails if sender has no eth
    deployer = ContractDeployer(
        web3=web3,
        private_key=get_random_privkey(),
        gas_limit=gas_limit,
        gas_price=1,
        wait=10,
    )
    with pytest.raises(ValidationError):
        deployer.deploy_token_contract(
            token_supply=10000000,
            token_decimals=18,
            token_name='TestToken',
            token_symbol='TTT',
            token_type='CustomToken',
        )
Example #14
0
    def get(privkey: Optional[str] = None) -> HexAddress:
        if not privkey:
            privkey = get_random_privkey()
        address = private_key_to_address(privkey)

        if not any((is_same_address(address, x) for x in ethereum_tester.get_accounts())):
            # account has not been added to ethereum_tester, yet
            ethereum_tester.add_account(privkey)

        for faucet in web3.eth.accounts[:10]:
            try:
                web3.eth.sendTransaction(
                    {"from": faucet, "to": address, "value": 1 * int(units["finney"])}
                )
                break
            except TransactionFailed:
                continue
        return address
Example #15
0
def test_deploy_script_raiden(
        web3,
        version: Optional[str],
        max_num_of_token_networks: Optional[int],
        deployer,
        deployed_raiden_info,
):
    """ Run raiden contracts deployment function and tamper with deployed_contracts_info

    This checks if deploy_raiden_contracts() works correctly in the happy case,
    to make sure no code dependencies have been changed, affecting the deployment script.
    This does not check however that the cli command works correctly.
    This also tampers with deployed_contracts_info to make sure an error is raised in
    verify_deployed_contracts()
    """
    deployed_contracts_info = deployed_raiden_info

    deployer._verify_deployment_data(
        deployment_data=deployed_contracts_info,
    )

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail['contracts_version'] = '0.0.0'
    with pytest.raises(AssertionError):
        deployer._verify_deployment_data(
            deployment_data=deployed_contracts_info_fail,
        )

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail['chain_id'] = 0
    with pytest.raises(AssertionError):
        deployer._verify_deployment_data(
            deployment_data=deployed_contracts_info_fail,
        )

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail['contracts'][
        CONTRACT_ENDPOINT_REGISTRY
    ]['address'] = EMPTY_ADDRESS
    with pytest.raises(AssertionError):
        deployer._verify_deployment_data(
            deployed_contracts_info_fail,
        )

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail['contracts'][CONTRACT_SECRET_REGISTRY]['address'] = EMPTY_ADDRESS
    with pytest.raises(AssertionError):
        deployer._verify_deployment_data(
            deployed_contracts_info_fail,
        )

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail['contracts'][
        CONTRACT_TOKEN_NETWORK_REGISTRY
    ]['address'] = EMPTY_ADDRESS
    with pytest.raises(AssertionError):
        deployer._verify_deployment_data(
            deployed_contracts_info_fail,
        )

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail['contracts'][CONTRACT_ENDPOINT_REGISTRY]['block_number'] = 0
    with pytest.raises(AssertionError):
        deployer._verify_deployment_data(
            deployed_contracts_info_fail,
        )

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail['contracts'][CONTRACT_SECRET_REGISTRY]['block_number'] = 0
    with pytest.raises(AssertionError):
        deployer._verify_deployment_data(
            deployed_contracts_info_fail,
        )

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail['contracts'][CONTRACT_TOKEN_NETWORK_REGISTRY]['block_number'] = 0
    with pytest.raises(AssertionError):
        deployer._verify_deployment_data(
            deployed_contracts_info_fail,
        )

    # check that it fails if sender has no eth
    deployer = ContractDeployer(
        web3=web3,
        private_key=get_random_privkey(),
        gas_limit=GAS_LIMIT,
        gas_price=1,
        wait=10,
    )
    with pytest.raises(ValidationError):
        deploy_raiden_contracts(deployer, 1)
Example #16
0
def test_get_paths_validation(
    api_sut: ServiceApi,
    api_url: str,
    initiator_address: str,
    target_address: str,
    token_network_model: TokenNetwork,
):
    url = api_url + f'/{token_network_model.address}/paths'
    default_params = {
        'from': initiator_address,
        'to': target_address,
        'value': 5,
        'max_paths': 3,
    }

    def request_path_with(status_code=400, **kwargs):
        params = default_params.copy()
        params.update(kwargs)
        response = requests.post(url, json=params)
        assert response.status_code == status_code, response.json()
        return response

    response = requests.post(url)
    assert response.status_code == 400
    assert response.json()['errors'].startswith('Required parameters:')

    response = request_path_with(**{'from': 'notanaddress'})
    assert response.json(
    )['errors'] == 'Invalid initiator address: notanaddress'

    response = request_path_with(to='notanaddress')
    assert response.json()['errors'] == 'Invalid target address: notanaddress'

    response = request_path_with(
        **{'from': to_normalized_address(initiator_address)})
    assert response.json(
    )['errors'] == 'Initiator address not checksummed: {}'.format(
        to_normalized_address(initiator_address), )

    response = request_path_with(to=to_normalized_address(target_address))
    assert response.json(
    )['errors'] == 'Target address not checksummed: {}'.format(
        to_normalized_address(target_address), )

    response = request_path_with(value=-10)
    assert response.json(
    )['errors'] == 'Payment value must be non-negative: -10'

    response = request_path_with(max_paths=-1)
    assert response.json()['errors'] == 'Number of paths must be positive: -1'

    # Exemplary test for payment errors. Different errors are serialized the
    # same way in the rest API. Checking for specific errors is tested in
    # payment_tests.
    api_sut.pathfinding_service.service_fee = 1
    response = request_path_with()
    assert response.json()['error_code'] == exceptions.MissingIOU.error_code

    # with successful payment
    iou = make_iou(get_random_privkey(), api_sut.pathfinding_service.address)
    response = request_path_with(iou=iou, status_code=200)

    # kill all running greenlets
    gevent.killall(
        [obj
         for obj in gc.get_objects() if isinstance(obj, gevent.Greenlet)], )
def test_crash(tmpdir, mockchain):  # pylint: disable=too-many-locals
    """Process blocks and compare results with/without crash

    A somewhat meaninful crash handling is simulated by not including the
    UpdatedHeadBlockEvent in every block.
    """
    token_address = TokenAddress(bytes([1] * 20))
    token_network_address = TokenNetworkAddress(bytes([2] * 20))
    channel_id = ChannelID(1)
    p1 = Address(bytes([3] * 20))
    p2 = Address(bytes([4] * 20))
    events = [
        [
            ReceiveTokenNetworkCreatedEvent(
                token_address=token_address,
                token_network_address=token_network_address,
                settle_timeout=DEFAULT_TOKEN_NETWORK_SETTLE_TIMEOUT,
                block_number=BlockNumber(1),
            )
        ],
        [UpdatedHeadBlockEvent(BlockNumber(2))],
        [
            ReceiveChannelOpenedEvent(
                token_network_address=token_network_address,
                channel_identifier=channel_id,
                participant1=p1,
                participant2=p2,
                block_number=BlockNumber(3),
            )
        ],
        [UpdatedHeadBlockEvent(BlockNumber(4))],
    ]
    mockchain(events)

    server_private_key = PrivateKey(get_random_privkey())
    contracts = {
        CONTRACT_TOKEN_NETWORK_REGISTRY: ContractMock(),
        CONTRACT_USER_DEPOSIT: ContractMock(),
    }

    def new_service(filename):
        service = PathfindingService(
            web3=Web3Mock(),
            private_key=server_private_key,
            contracts=contracts,
            sync_start_block=BlockNumber(0),
            required_confirmations=BlockTimeout(0),
            poll_interval=0,
            db_filename=os.path.join(tmpdir, filename),
        )
        return service

    # initialize stable service
    stable_service = new_service("stable.db")

    # process each block and compare results between crashy and stable service
    for to_block in range(len(events)):
        crashy_service = new_service("crashy.db")  # new instance to simulate crash
        result_state: List[dict] = []
        for service in [stable_service, crashy_service]:
            service._process_new_blocks(BlockNumber(to_block))  # pylint: disable=protected-access
            result_state.append(dict(db_dump=list(service.database.conn.iterdump())))

        # both instances should have the same state after processing
        for stable_state, crashy_state in zip(result_state[0].values(), result_state[1].values()):
            if isinstance(stable_state, BlockchainState):
                assert stable_state.chain_id == crashy_state.chain_id
                assert (
                    stable_state.token_network_registry_address
                    == crashy_state.token_network_registry_address
                )
                assert stable_state.latest_committed_block == crashy_state.latest_committed_block
                assert (
                    stable_state.monitor_contract_address == crashy_state.monitor_contract_address
                )
                # Do not compare `current_event_filter_interval`, this is allowed to be different
            else:
                assert stable_state == crashy_state

        crashy_service.database.conn.close()  # close the db connection so we can access it again
Example #18
0
def test_get_paths_validation(
    api_sut: ServiceApi,
    api_url: str,
    addresses: List[Address],
    token_network_model: TokenNetwork,
    make_iou,
):
    initiator_address = to_checksum_address(addresses[0])
    target_address = to_checksum_address(addresses[1])
    url = api_url + "/" + to_checksum_address(token_network_model.address) + "/paths"
    default_params = {"from": initiator_address, "to": target_address, "value": 5, "max_paths": 3}

    def request_path_with(status_code=400, **kwargs):
        params = default_params.copy()
        params.update(kwargs)
        response = requests.post(url, json=params)
        assert response.status_code == status_code, response.json()
        return response

    response = requests.post(url)
    assert response.status_code == 400
    assert response.json()["errors"].startswith("JSON payload expected")

    for address in ["notanaddress", to_normalized_address(initiator_address)]:
        response = request_path_with(**{"from": address})
        assert response.json()["error_code"] == exceptions.InvalidRequest.error_code
        assert "from" in response.json()["error_details"]

        response = request_path_with(to=address)
        assert response.json()["error_code"] == exceptions.InvalidRequest.error_code
        assert "to" in response.json()["error_details"]

    response = request_path_with(value=-10)
    assert response.json()["error_code"] == exceptions.InvalidRequest.error_code
    assert "value" in response.json()["error_details"]

    response = request_path_with(max_paths=-1)
    assert response.json()["error_code"] == exceptions.InvalidRequest.error_code
    assert "max_paths" in response.json()["error_details"]

    # successful request without payment
    request_path_with(status_code=200)

    # Exemplary test for payment errors. Different errors are serialized the
    # same way in the rest API. Checking for specific errors is tested in
    # payment_tests.
    api_sut.service_fee = TokenAmount(1)
    response = request_path_with()
    assert response.json()["error_code"] == exceptions.MissingIOU.error_code

    # prepare iou for payment tests
    iou = make_iou(
        get_random_privkey(),
        api_sut.pathfinding_service.address,
        one_to_n_address=api_sut.one_to_n_address,
    )
    good_iou_dict = iou.Schema().dump(iou)

    # malformed iou
    bad_iou_dict = good_iou_dict.copy()
    del bad_iou_dict["amount"]
    response = request_path_with(iou=bad_iou_dict)
    assert response.json()["error_code"] == exceptions.InvalidRequest.error_code

    # bad signature
    bad_iou_dict = good_iou_dict.copy()
    bad_iou_dict["signature"] = "0x" + "1" * 130
    response = request_path_with(iou=bad_iou_dict)
    assert response.json()["error_code"] == exceptions.InvalidSignature.error_code

    # with successful payment
    request_path_with(iou=good_iou_dict, status_code=200)
Example #19
0
def test_get_paths_validation(
    api_sut: ServiceApi,
    api_url: str,
    addresses: List[Address],
    token_network_model: TokenNetwork,
    make_iou: Callable,
):
    initiator_address = to_checksum_address(addresses[0])
    target_address = to_checksum_address(addresses[1])
    url = api_url + "/" + to_checksum_address(
        token_network_model.address) + "/paths"
    default_params = {
        "from": initiator_address,
        "to": target_address,
        "value": 5,
        "max_paths": 3
    }

    def request_path_with(status_code=400, **kwargs):
        params = default_params.copy()
        params.update(kwargs)
        response = requests.post(url, json=params)
        assert response.status_code == status_code, response.json()
        return response

    response = requests.post(url)
    assert response.status_code == 400
    assert response.json()["errors"].startswith("JSON payload expected")

    for address in ["notanaddress", to_normalized_address(initiator_address)]:
        response = request_path_with(**{"from": address})
        assert response.json(
        )["error_code"] == exceptions.InvalidRequest.error_code
        assert "from" in response.json()["error_details"]

        response = request_path_with(to=address)
        assert response.json(
        )["error_code"] == exceptions.InvalidRequest.error_code
        assert "to" in response.json()["error_details"]

    response = request_path_with(value=-10)
    assert response.json(
    )["error_code"] == exceptions.InvalidRequest.error_code
    assert "value" in response.json()["error_details"]

    response = request_path_with(max_paths=-1)
    assert response.json(
    )["error_code"] == exceptions.InvalidRequest.error_code
    assert "max_paths" in response.json()["error_details"]

    # successful request without payment
    request_path_with(status_code=200)

    # Exemplary test for payment errors. Different errors are serialized the
    # same way in the rest API. Checking for specific errors is tested in
    # payment_tests.
    api_sut.service_fee = TokenAmount(1)
    response = request_path_with()
    assert response.json()["error_code"] == exceptions.MissingIOU.error_code

    # prepare iou for payment tests
    iou = make_iou(
        get_random_privkey(),
        api_sut.pathfinding_service.address,
        one_to_n_address=api_sut.one_to_n_address,
    )
    good_iou_dict = iou.Schema().dump(iou)

    # malformed iou
    bad_iou_dict = good_iou_dict.copy()
    del bad_iou_dict["amount"]
    response = request_path_with(iou=bad_iou_dict)
    assert response.json(
    )["error_code"] == exceptions.InvalidRequest.error_code

    # malformed iou
    bad_iou_dict = {
        "amount": {
            "_hex": "0x64"
        },
        "chain_id": {
            "_hex": "0x05"
        },
        "expiration_block": {
            "_hex": "0x188cba"
        },
        "one_to_n_address":
        "0x0000000000000000000000000000000000000000",
        "receiver":
        "0x94DEe8e391410A9ebbA791B187df2d993212c849",
        "sender":
        "0x2046F7341f15D0211ca1EBeFb19d029c4Bc4c4e7",
        "signature":
        ("0x0c3066e6a954d660028695f96dfe88cabaf0bc8a385e51781ac4d21003d0b6cd7a8b2"
         "a1134115845655d1a509061f48459cd401565b5df7845c913ed329cd2351b"),
    }
    response = request_path_with(iou=bad_iou_dict)
    assert response.json(
    )["error_code"] == exceptions.InvalidRequest.error_code

    # bad signature
    bad_iou_dict = good_iou_dict.copy()
    bad_iou_dict["signature"] = "0x" + "1" * 130
    response = request_path_with(iou=bad_iou_dict)
    assert response.json(
    )["error_code"] == exceptions.InvalidSignature.error_code

    # with successful payment
    request_path_with(iou=good_iou_dict, status_code=200)
Example #20
0
def test_get_paths_validation(
    api_sut: ServiceApi,
    api_url: str,
    initiator_address: str,
    target_address: str,
    token_network_model: TokenNetwork,
):
    url = api_url + f'/{token_network_model.address}/paths'
    default_params = {'from': initiator_address, 'to': target_address, 'value': 5, 'max_paths': 3}

    def request_path_with(status_code=400, **kwargs):
        params = default_params.copy()
        params.update(kwargs)
        response = requests.post(url, json=params)
        assert response.status_code == status_code, response.json()
        return response

    response = requests.post(url)
    assert response.status_code == 400
    assert response.json()['errors'].startswith('JSON payload expected')

    for address in ['notanaddress', to_normalized_address(initiator_address)]:
        response = request_path_with(**{'from': address})
        assert response.json()['error_code'] == exceptions.InvalidRequest.error_code
        assert 'from' in response.json()['error_details']

        response = request_path_with(to=address)
        assert response.json()['error_code'] == exceptions.InvalidRequest.error_code
        assert 'to' in response.json()['error_details']

    response = request_path_with(value=-10)
    assert response.json()['error_code'] == exceptions.InvalidRequest.error_code
    assert 'value' in response.json()['error_details']

    response = request_path_with(max_paths=-1)
    assert response.json()['error_code'] == exceptions.InvalidRequest.error_code
    assert 'max_paths' in response.json()['error_details']

    # Exemplary test for payment errors. Different errors are serialized the
    # same way in the rest API. Checking for specific errors is tested in
    # payment_tests.
    api_sut.pathfinding_service.service_fee = 1
    response = request_path_with()
    assert response.json()['error_code'] == exceptions.MissingIOU.error_code

    # prepare iou for payment tests
    iou = make_iou(get_random_privkey(), api_sut.pathfinding_service.address)
    good_iou_dict = iou.Schema().dump(iou)[0]

    # malformed iou
    bad_iou_dict = good_iou_dict.copy()
    del bad_iou_dict['amount']
    response = request_path_with(iou=bad_iou_dict)
    assert response.json()['error_code'] == exceptions.InvalidRequest.error_code

    # bad signature
    bad_iou_dict = good_iou_dict.copy()
    bad_iou_dict['signature'] = hex(int(bad_iou_dict['signature'], 16) + 1)
    response = request_path_with(iou=bad_iou_dict)
    assert response.json()['error_code'] == exceptions.InvalidSignature.error_code

    # with successful payment
    response = request_path_with(iou=good_iou_dict, status_code=200)

    # kill all running greenlets
    gevent.killall([obj for obj in gc.get_objects() if isinstance(obj, gevent.Greenlet)])
def test_deploy_script_raiden(web3: Web3, deployer: ContractDeployer,
                              deployed_raiden_info: DeployedContracts) -> None:
    """ Run raiden contracts deployment function and tamper with deployed_contracts_info

    This checks if deploy_raiden_contracts() works correctly in the happy case,
    to make sure no code dependencies have been changed, affecting the deployment script.
    This does not check however that the cli command works correctly.
    This also tampers with deployed_contracts_info to make sure an error is raised in
    verify_deployed_contracts()
    """
    deployed_contracts_info = deployed_raiden_info

    deployer.verify_deployment_data(deployment_data=deployed_contracts_info)

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail["contracts_version"] = "0.0.0"
    with pytest.raises(RuntimeError):
        deployer.verify_deployment_data(
            deployment_data=deployed_contracts_info_fail)

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail["chain_id"] = 0
    with pytest.raises(RuntimeError):
        deployer.verify_deployment_data(
            deployment_data=deployed_contracts_info_fail)

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail["contracts"][CONTRACT_SECRET_REGISTRY][
        "address"] = EMPTY_ADDRESS
    with pytest.raises(RuntimeError):
        deployer.verify_deployment_data(deployed_contracts_info_fail)

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail["contracts"][CONTRACT_SECRET_REGISTRY][
        "address"] = EMPTY_ADDRESS
    with pytest.raises(RuntimeError):
        deployer.verify_deployment_data(deployed_contracts_info_fail)

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail["contracts"][CONTRACT_TOKEN_NETWORK_REGISTRY][
        "address"] = EMPTY_ADDRESS
    with pytest.raises(RuntimeError):
        deployer.verify_deployment_data(deployed_contracts_info_fail)

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail["contracts"][CONTRACT_SECRET_REGISTRY][
        "block_number"] = 0
    with pytest.raises(RuntimeError):
        deployer.verify_deployment_data(deployed_contracts_info_fail)

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail["contracts"][CONTRACT_SECRET_REGISTRY][
        "block_number"] = 0
    with pytest.raises(RuntimeError):
        deployer.verify_deployment_data(deployed_contracts_info_fail)

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail["contracts"][CONTRACT_TOKEN_NETWORK_REGISTRY][
        "block_number"] = 0
    with pytest.raises(RuntimeError):
        deployer.verify_deployment_data(deployed_contracts_info_fail)

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail["contracts"][CONTRACT_TOKEN_NETWORK_REGISTRY][
        "gas_cost"] = 0
    with pytest.raises(RuntimeError):
        deployer.verify_deployment_data(deployed_contracts_info_fail)

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail["contracts"][CONTRACT_TOKEN_NETWORK_REGISTRY][
        "address"] = EMPTY_ADDRESS
    with pytest.raises(RuntimeError):
        deployer.verify_deployment_data(deployed_contracts_info_fail)

    deployed_contracts_info_fail = deepcopy(deployed_contracts_info)
    deployed_contracts_info_fail["contracts_version"] = "0.4.0"
    with pytest.raises(RuntimeError):
        deployer.verify_deployment_data(deployed_contracts_info_fail)

    # check that it fails if sender has no eth
    deployer = ContractDeployer(web3=web3,
                                private_key=get_random_privkey(),
                                gas_limit=GAS_LIMIT,
                                gas_price=1,
                                wait=10)
    with pytest.raises(ValidationError):
        deployer.deploy_raiden_contracts(1)
Example #22
0
def test_crash(tmpdir, get_accounts, get_private_key, mockchain):  # pylint: disable=too-many-locals
    """ Process blocks and compare results with/without crash

    A somewhat meaninful crash handling is simulated by not including the
    UpdatedHeadBlockEvent in every block.
    """
    channel_identifier = ChannelID(3)
    c1, c2 = get_accounts(2)
    token_network_address = TokenNetworkAddress(
        to_canonical_address(get_random_address()))
    balance_proof = HashedBalanceProof(
        nonce=Nonce(1),
        transferred_amount=TokenAmount(2),
        priv_key=get_private_key(c1),
        channel_identifier=channel_identifier,
        token_network_address=token_network_address,
        chain_id=ChainID(1),
        additional_hash="0x%064x" % 0,
        locked_amount=0,
        locksroot=encode_hex(LOCKSROOT_OF_NO_LOCKS),
    )
    monitor_request = balance_proof.get_monitor_request(
        get_private_key(c2),
        reward_amount=TokenAmount(0),
        msc_address=TEST_MSC_ADDRESS)

    events = [
        [
            ReceiveChannelOpenedEvent(
                token_network_address=token_network_address,
                channel_identifier=channel_identifier,
                participant1=c1,
                participant2=c2,
                settle_timeout=20,
                block_number=BlockNumber(0),
            )
        ],
        [UpdatedHeadBlockEvent(BlockNumber(1))],
        [
            ActionMonitoringTriggeredEvent(
                token_network_address=token_network_address,
                channel_identifier=channel_identifier,
                non_closing_participant=c2,
            )
        ],
        [UpdatedHeadBlockEvent(BlockNumber(3))],
    ]
    mockchain(events)

    server_private_key = get_random_privkey()

    contracts = {
        CONTRACT_TOKEN_NETWORK_REGISTRY: ContractMock(),
        CONTRACT_MONITORING_SERVICE: ContractMock(),
        CONTRACT_USER_DEPOSIT: ContractMock(),
        CONTRACT_SERVICE_REGISTRY: ContractMock(),
    }

    def new_ms(filename):
        ms = MonitoringService(
            web3=Web3Mock(),
            private_key=server_private_key,
            contracts=contracts,
            db_filename=os.path.join(tmpdir, filename),
        )
        msc = Mock()
        ms.context.monitoring_service_contract = msc
        ms.monitor_mock = msc.functions.monitor.return_value.transact  # type: ignore
        ms.monitor_mock.return_value = bytes(0)  # type: ignore
        return ms

    # initialize both monitoring services
    stable_ms = new_ms("stable.db")
    crashy_ms = new_ms("crashy.db")
    for ms in [stable_ms, crashy_ms]:
        ms.database.conn.execute(
            "INSERT INTO token_network(address) VALUES (?)",
            [to_checksum_address(token_network_address)],
        )
        ms.context.ms_state.blockchain_state.token_network_addresses = [
            token_network_address
        ]
        ms.database.upsert_monitor_request(monitor_request)
        ms.database.conn.commit()

    # process each block and compare results between crashy and stable ms
    for to_block in range(len(events)):
        crashy_ms = new_ms("crashy.db")  # new instance to simulate crash
        stable_ms.monitor_mock.reset_mock()  # clear calls from last block
        result_state: List[dict] = []
        for ms in [stable_ms, crashy_ms]:
            ms._process_new_blocks(to_block)  # pylint: disable=protected-access
            result_state.append(
                dict(
                    blockchain_state=ms.context.ms_state.blockchain_state,
                    db_dump=list(ms.database.conn.iterdump()),
                    monitor_calls=ms.monitor_mock.mock_calls,
                ))

        # both instances should have the same state after processing
        for stable_state, crashy_state in zip(result_state[0].values(),
                                              result_state[1].values()):
            # do asserts for each key separately to get better error messages
            assert stable_state == crashy_state
Example #23
0
def server_private_key(ethereum_tester):
    key = get_random_privkey()
    ethereum_tester.add_account(key)
    return key
Example #24
0
def test_save_and_load_iou(pathfinding_service_mock, make_iou):
    pfs = pathfinding_service_mock
    iou = make_iou(get_random_privkey(), pfs.address)
    pfs.database.upsert_iou(iou)
    stored_iou = pfs.database.get_iou(iou.sender, iou.expiration_block)
    assert stored_iou == iou
Example #25
0
def test_crash(tmpdir, mockchain):  # pylint: disable=too-many-locals
    """ Process blocks and compare results with/without crash

    A somewhat meaninful crash handling is simulated by not including the
    UpdatedHeadBlockEvent in every block.
    """
    token_address = Address("0x" + "1" * 40)
    token_network_address = TokenNetworkAddress("0x" + "2" * 40)
    channel_id = ChannelID(1)
    p1 = Address("0x" + "3" * 40)
    p2 = Address("0x" + "4" * 40)
    events = [
        [
            ReceiveTokenNetworkCreatedEvent(
                token_address=token_address,
                token_network_address=token_network_address,
                block_number=BlockNumber(1),
            )
        ],
        [UpdatedHeadBlockEvent(BlockNumber(2))],
        [
            ReceiveChannelOpenedEvent(
                token_network_address=token_network_address,
                channel_identifier=channel_id,
                participant1=p1,
                participant2=p2,
                settle_timeout=1000,
                block_number=BlockNumber(3),
            )
        ],
        [UpdatedHeadBlockEvent(BlockNumber(4))],
    ]
    mockchain(events)

    server_private_key = get_random_privkey()
    contracts = {
        CONTRACT_TOKEN_NETWORK_REGISTRY: ContractMock(),
        CONTRACT_USER_DEPOSIT: ContractMock(),
    }

    def new_service(filename):
        service = PathfindingService(
            web3=Web3Mock(),
            private_key=server_private_key,
            contracts=contracts,
            db_filename=os.path.join(tmpdir, filename),
        )
        return service

    # initialize stable service
    stable_service = new_service("stable.db")

    # process each block and compare results between crashy and stable service
    for to_block in range(len(events)):
        crashy_service = new_service(
            "crashy.db")  # new instance to simulate crash
        result_state: List[dict] = []
        for service in [stable_service, crashy_service]:
            service._process_new_blocks(BlockNumber(to_block))  # pylint: disable=protected-access
            result_state.append(
                dict(db_dump=list(service.database.conn.iterdump())))

        # both instances should have the same state after processing
        for stable_state, crashy_state in zip(result_state[0].values(),
                                              result_state[1].values()):
            # do asserts for each key separately to get better error messages
            assert stable_state == crashy_state