Exemple #1
0
 def _process_response(self, response_dict: dict):
     for field in ['balance', 'total_deposit', 'state']:
         # The task parameter field names are the channel field names with a `_sum` suffix
         assert_field = f'{field}_sum'
         if assert_field not in self._config:
             continue
         assert_value = self._config[assert_field]
         if field == 'state':
             # Special case state since it's a string field
             channel_states = {
                 channel['state']
                 for channel in response_dict
             }
             if len(channel_states) > 1:
                 raise ScenarioAssertionError(
                     f'Expected all channels to be in "{assert_value}" state. '
                     f'Found: {channel_states}', )
             channel_value_sum = first(channel_states)
         else:
             channel_value_sum = sum(channel[field]
                                     for channel in response_dict)
         if assert_value != channel_value_sum:
             raise ScenarioAssertionError(
                 f'Expected sum value "{assert_value}" for channel fields "{field}". '
                 f'Actual value: "{channel_value_sum}". '
                 f'Channels: {response_dict}', )
Exemple #2
0
    def _process_response(self, response_dict: dict):
        response_dict = super()._process_response(response_dict)
        for field in ["balance", "total_deposit", "state"]:
            if field not in self._config:
                continue
            if field not in response_dict:
                raise ScenarioAssertionError(
                    f'Field "{field}" is missing in channel: {response_dict}')
            allow_error = self._config.get("allow_" + field + "_error")
            if allow_error:
                success = (int(response_dict[field]) - allow_error <=
                           self._config[field] <=
                           int(response_dict[field]) + allow_error)
                log.info("allow_error",
                         allow_error=allow_error,
                         error_success=success)
            else:
                success = str(response_dict[field]) == str(self._config[field])

            if not success:
                raise ScenarioAssertionError(
                    f'Value mismatch for "{field}". '
                    f'Should: "{self._config[field]}" '
                    f'Is: "{response_dict[field]}" '
                    f"Channel: {response_dict}")
        return response_dict
    def _run(self, *args, **kwargs) -> Dict[str, Any]:  # pylint: disable=unused-argument
        channel_infos = self._runner.task_storage[
            STORAGE_KEY_CHANNEL_INFO].get(self._config["channel_info_key"])

        if channel_infos is None:
            raise ScenarioError(
                f"No stored channel info found for key '{self._config['channel_info_key']}'."
            )

        # calculate reward_id
        assert "token_network_address" in channel_infos.keys()
        assert "channel_identifier" in channel_infos.keys()

        reward_id = bytes(
            Web3.soliditySha3(  # pylint: disable=no-value-for-parameter
                ["uint256", "address"],
                [
                    int(channel_infos["channel_identifier"]),
                    channel_infos["token_network_address"],
                ],
            ))

        log.info("Calculated reward ID", reward_id=encode_hex(reward_id))

        events = query_blockchain_events(
            web3=self.web3,
            contract_manager=self._runner.contract_manager,
            contract_address=to_canonical_address(self.contract_address),
            contract_name=self.contract_name,
            topics=[],
            from_block=BlockNumber(self._runner.block_execution_started),
            to_block=BlockNumber(self.web3.eth.blockNumber),
        )

        # Filter matching events
        def match_event(event: Dict):
            if not event["event"] == MonitoringServiceEvent.REWARD_CLAIMED:
                return False

            event_reward_id = bytes(event["args"]["reward_identifier"])
            return event_reward_id == reward_id

        events = [e for e in events if match_event(e)]
        log.info("Matching events", events=events)

        must_claim = self._config.get("must_claim", True)
        found_events = len(events) > 0

        # Raise exception when no event was found
        if must_claim and not found_events:
            raise ScenarioAssertionError(
                "No RewardClaimed event found for this channel.")
        elif not must_claim and found_events:
            raise ScenarioAssertionError(
                "Unexpected RewardClaimed event found for this channel.")

        return {"events": events}
    def _process_response(self, response_dict: dict):
        paths = response_dict.get("result")
        if paths is None:
            raise ScenarioAssertionError("No 'result' key in result from PFS")

        num_paths = len(paths)
        exptected_paths = int(self._config["expected_paths"])
        if num_paths != exptected_paths:
            log.debug("Received paths", paths=paths)
            raise ScenarioAssertionError(
                f"Expected {exptected_paths} paths, but PFS returned {num_paths} paths."
            )
Exemple #5
0
    def _process_response(self, response_dict: dict):
        exp_request_count = self._config.get('request_count')
        if exp_request_count:
            actual_request_count = response_dict['request_count']
            if actual_request_count != exp_request_count:
                raise ScenarioAssertionError(
                    f'Expected request_count {exp_request_count} but got {actual_request_count}',
                )

        actual_routes_counts = [
            len(response['routes']) for response in response_dict['responses']
        ]
        exp_routes_counts = self._config.get('routes_count')
        if exp_routes_counts:
            if isinstance(exp_routes_counts, int):
                request_count = exp_request_count if exp_request_count else 1
                exp_routes_counts = [exp_routes_counts] * request_count
            elif isinstance(exp_routes_counts, (list, tuple)):
                if len(exp_routes_counts) != len(actual_routes_counts):
                    raise ScenarioAssertionError(
                        f'Expected {len(exp_routes_counts)} routes but got '
                        f'{len(actual_routes_counts)}', )

            loop_iterator = enumerate(
                zip(exp_routes_counts, actual_routes_counts))
            for i, (exp_route_count, actual_route_count) in loop_iterator:
                if exp_route_count != actual_route_count:
                    raise ScenarioAssertionError(
                        f'Expected route count {exp_route_count} but got {actual_route_count} '
                        f'at index {i}', )

        actual_routes = [
            route['path'] for response in response_dict['responses']
            for route in response['routes'] if response['routes']
        ]

        exp_routes = self._config.get('expected_routes')
        if exp_routes:
            if len(exp_routes) != len(actual_routes):
                raise ScenarioAssertionError(
                    f'Expected {len(exp_routes)} routes but got {len(actual_routes)}.',
                )
            for i, (exp_route,
                    actual_route) in enumerate(zip(exp_routes, actual_routes)):
                exp_route_addr = [
                    self._runner.get_node_address(node) for node in exp_route
                ]
                if exp_route_addr != actual_route:
                    raise ScenarioAssertionError(
                        f'Expected route {exp_route} but got {actual_route} at index {i}',
                    )
    def _process_response(self, response_dict: dict):

        if self._config.get("iou_exists", True) is False:
            if response_dict:
                raise ScenarioAssertionError(f"Expected no IOU but got {response_dict}.")
        elif not response_dict:
            raise ScenarioAssertionError(f"Expected IOU, but no IOU exists.")
        else:
            exp_iou_amount = int(self._config["amount"])
            actual_iou_amount = int(response_dict["amount"])
            if actual_iou_amount != exp_iou_amount:
                raise ScenarioAssertionError(
                    f"Expected amount of {exp_iou_amount} but got {actual_iou_amount}."
                )
Exemple #7
0
 def _process_response(self, response_dict: dict):
     response_dict = super()._process_response(response_dict)
     for field in ['balance', 'total_deposit', 'state']:
         if field not in self._config:
             continue
         if field not in response_dict:
             raise ScenarioAssertionError(
                 f'Field "{field}" is missing in channel: {response_dict}',
             )
         if response_dict[field] != self._config[field]:
             raise ScenarioAssertionError(
                 f'Value mismatch for "{field}". '
                 f'Should: "{self._config[field]}" '
                 f'Is: "{response_dict[field]}" '
                 f'Channel: {response_dict}', )
    def _run(self, *args, **kwargs):  # pylint: disable=unused-argument
        # get the correct contract address
        # this has to be done in `_run`, otherwise `_runner` is not initialized yet
        contract_data = get_contracts_deployment_info(
            chain_id=self._runner.chain_id, version=DEVELOPMENT_CONTRACT_VERSION
        )
        if self.contract_name == CONTRACT_TOKEN_NETWORK:
            self.contract_address = self._runner.token_network_address
        else:
            try:
                contract_info = contract_data["contracts"][self.contract_name]
                self.contract_address = contract_info["address"]
            except KeyError:
                raise ScenarioError(f"Unknown contract name: {self.contract_name}")

        events = query_blockchain_events(
            web3=self.web3,
            contract_manager=self._runner.contract_manager,
            contract_address=self.contract_address,
            contract_name=self.contract_name,
            topics=[],
            from_block=BlockNumber(self._runner.token.deployment_block),
            to_block=BlockNumber(self.web3.eth.blockNumber),
        )

        # Filter matching events
        events = [e for e in events if e["event"] == self.event_name]

        # Raise exception when events do not match
        if not self.num_events == len(events):
            raise ScenarioAssertionError(
                f"Expected number of events ({self.num_events}) did not match the number "
                f"of events found ({len(events)})"
            )
    def _run(self, *args, **kwargs) -> Dict[str, Any]:  # pylint: disable=unused-argument
        # get the correct contract address
        # this has to be done in `_run`, otherwise `_runner` is not initialized yet
        contract_data = get_contracts_deployment_info(
            chain_id=self._runner.definition.settings.chain_id,
            version=RAIDEN_CONTRACT_VERSION,
            development_environment=self._runner.environment.
            development_environment,
        )
        if self.contract_name == CONTRACT_TOKEN_NETWORK:
            self.contract_address = self._runner.token_network_address
        else:
            try:
                assert contract_data
                contract_info = contract_data["contracts"][self.contract_name]
                self.contract_address = to_checksum_address(
                    contract_info["address"])
            except KeyError:
                raise ScenarioError(
                    f"Unknown contract name: {self.contract_name}")

        assert self.contract_address, "Contract address not set"
        events = query_blockchain_events(
            web3=self.web3,
            contract_manager=self._runner.contract_manager,
            contract_address=to_canonical_address(self.contract_address),
            contract_name=self.contract_name,
            topics=[],
            from_block=BlockNumber(self._runner.block_execution_started),
            to_block=BlockNumber(self.web3.eth.blockNumber),
        )

        # Filter matching events
        events = [e for e in events if e["event"] == self.event_name]

        if self.event_args:
            for key, value in self.event_args.items():
                if "participant" in key:
                    if isinstance(value, int) or (isinstance(value, str)
                                                  and value.isnumeric()):
                        # Replace node index with eth address
                        self.event_args[key] = self._runner.get_node_address(
                            int(value))

            event_args_items = self.event_args.items()
            # Filter the events by the given event args.
            # `.items()` produces a set like object which supports intersection (`&`)
            events = [
                e for e in events
                if e["args"] and event_args_items & e["args"].items()
            ]

        # Raise exception when events do not match
        if not self.num_events == len(events):
            raise ScenarioAssertionError(
                f"Expected number of events ({self.num_events}) did not match the number "
                f"of events found ({len(events)})")

        return {"events": events}
Exemple #10
0
 def _process_response(self, response_dict: dict):
     response_dict = super()._process_response(response_dict)
     channel_count = len(response_dict)
     for field in ["balance", "total_deposit", "state"]:
         # The task parameter field names are the plural of the channel field names
         assert_field = f"{field}s"
         if assert_field not in self._config:
             continue
         try:
             channel_field_values = [channel[field] for channel in response_dict]
         except KeyError:
             raise ScenarioAssertionError(
                 f'Field "{field}" is missing in at least one channel: {response_dict}'
             )
         assert_field_value_count = len(self._config[assert_field])
         if assert_field_value_count != channel_count:
             direction = ["many", "few"][assert_field_value_count < channel_count]
             raise ScenarioAssertionError(
                 f'Assertion field "{field}" has too {direction} values. '
                 f"Have {channel_count} channels but {assert_field_value_count} values."
             )
         channel_field_values_all = channel_field_values[:]
         for value in self._config[assert_field]:
             try:
                 channel_field_values.remove(value)
             except ValueError:
                 channel_field_values_str = ", ".join(
                     str(val) for val in channel_field_values_all
                 )
                 assert_field_values_str = ", ".join(
                     str(val) for val in self._config[assert_field]
                 )
                 raise ScenarioAssertionError(
                     f'Expected value "{value}" for field "{field}" not found in any channel. '
                     f"Existing values: {channel_field_values_str} "
                     f"Expected values: {assert_field_values_str} "
                     f"Channels: {response_dict}"
                 ) from None
         if len(channel_field_values) != 0:
             raise ScenarioAssertionError(
                 f'Value mismatch for field "{field}". '
                 f"Not all values consumed, remaining: {channel_field_values}"
             )
     return response_dict
    def _process_response(self, response_dict: Dict[str, Any]):
        if self._config.get("iou_exists", True) is False:
            if response_dict:
                raise ScenarioAssertionError(
                    f"Expected no IOU but got {response_dict}.")

            # Returning an empty dict would lead to the base task retrying
            return {"iou_exists": False}
        else:
            if not response_dict:
                raise ScenarioAssertionError(
                    "Expected IOU, but no IOU exists.")

            exp_iou_amount = int(self._config["amount"])
            actual_iou_amount = int(response_dict["amount"])
            if actual_iou_amount != exp_iou_amount:
                raise ScenarioAssertionError(
                    f"Expected amount of {exp_iou_amount} but got {actual_iou_amount}."
                )
            return response_dict
Exemple #12
0
    def _run(self, *args, **kwargs):  # pylint: disable=unused-argument
        channel_infos = self._runner.task_storage[STORAGE_KEY_CHANNEL_INFO].get(
            self._config['channel_info_key'],
        )

        if channel_infos is None:
            raise ScenarioError(
                f"No stored channel info found for key '{self._config['channel_info_key']}'.",
            )

        # calculate reward_id
        assert 'token_network_identifier' in channel_infos.keys()
        assert 'channel_identifier' in channel_infos.keys()

        reward_id = bytes(Web3.soliditySha3(  # pylint: disable=no-value-for-parameter
            ['uint256', 'address'],
            [channel_infos['channel_identifier'], channel_infos['token_network_identifier']],
        ))

        log.info('Calculated reward ID', reward_id=encode_hex(reward_id))

        events = query_blockchain_events(
            web3=self.web3,
            contract_manager=self._runner.contract_manager,
            contract_address=self.contract_address,
            contract_name=self.contract_name,
            topics=[],
            from_block=BlockNumber(self._runner.token_deployment_block),
            to_block=BlockNumber(self.web3.eth.blockNumber),
        )

        # Filter matching events
        def match_event(event: Dict):
            if not event['event'] == MonitoringServiceEvent.REWARD_CLAIMED:
                return False

            event_reward_id = bytes(event['args']['reward_identifier'])
            return event_reward_id == reward_id

        events = [e for e in events if match_event(e)]
        log.info('Matching events', events=events)

        # Raise exception when no event was found
        if len(events) == 0:
            raise ScenarioAssertionError('No RewardClaimed event found for this channel.')
Exemple #13
0
    def _run(self, *args, **kwargs):
        events = query_blockchain_events(
            web3=self.web3,
            contract_manager=self._runner.contract_manager,
            contract_address=self._runner.token_network_address,
            contract_name=CONTRACT_TOKEN_NETWORK,
            topics=[],
            from_block=BlockNumber(self._runner.token_deployment_block),
            to_block=BlockNumber(self.web3.eth.blockNumber),
        )

        # Filter matching events
        events = [e for e in events if e['event'] == self.event_name]

        # Raise exception when events do not match
        if not self.num_events == len(events):
            raise ScenarioAssertionError(
                f'Expected number of events ({self.num_events}) did not match the number '
                f'of events found ({len(events)})', )
    def _process_response(self, response_dict: dict):
        exp_request_count = self._config.get("request_count")
        if exp_request_count:
            actual_request_count = response_dict["request_count"]
            if actual_request_count != exp_request_count:
                raise ScenarioAssertionError(
                    f"Expected request_count {exp_request_count} but got {actual_request_count}"
                )

        actual_routes_counts = [len(response["routes"]) for response in response_dict["responses"]]
        exp_routes_counts = self._config.get("routes_count")
        if exp_routes_counts:
            if isinstance(exp_routes_counts, int):
                request_count = exp_request_count if exp_request_count else 1
                exp_routes_counts = [exp_routes_counts] * request_count
            elif isinstance(exp_routes_counts, (list, tuple)):
                if len(exp_routes_counts) != len(actual_routes_counts):
                    raise ScenarioAssertionError(
                        f"Expected {len(exp_routes_counts)} routes but got "
                        f"{len(actual_routes_counts)}"
                    )

            loop_iterator = enumerate(zip(exp_routes_counts, actual_routes_counts))
            for i, (exp_route_count, actual_route_count) in loop_iterator:
                if exp_route_count != actual_route_count:
                    raise ScenarioAssertionError(
                        f"Expected route count {exp_route_count} but got {actual_route_count} "
                        f"at index {i}"
                    )

        actual_routes = [
            route["path"]
            for response in response_dict["responses"]
            for route in response["routes"]
            if response["routes"]
        ]

        exp_routes = self._config.get("expected_routes")
        if exp_routes:
            if len(exp_routes) != len(actual_routes):
                raise ScenarioAssertionError(
                    f"Expected {len(exp_routes)} routes but got {len(actual_routes)}."
                )
            for i, (exp_route, actual_route) in enumerate(zip(exp_routes, actual_routes)):
                exp_route_addr = [self._runner.get_node_address(node) for node in exp_route]
                if exp_route_addr != actual_route:
                    raise ScenarioAssertionError(
                        f"Expected route {exp_route} but got {actual_route} at index {i}"
                    )

        exp_fees = self._config.get("expected_fees")
        if exp_fees:
            actual_fees = [
                route["estimated_fee"]
                for response in response_dict["responses"]
                for route in response["routes"]
                if response["routes"]
            ]
            if len(exp_fees) != len(actual_fees):
                raise ScenarioAssertionError(
                    f"Expected {len(exp_fees)} fees but got {len(actual_fees)}."
                )
            for i, (exp_fee, actual_fee) in enumerate(zip(exp_fees, actual_fees)):
                if exp_fee != actual_fee:
                    raise ScenarioAssertionError(
                        f"Expected fee {exp_fee} but got {actual_fee} at index {i}"
                    )
Exemple #15
0
    def _process_response(self, response_dict: dict):
        exp_request_count = self._config.get("request_count")
        if exp_request_count:
            actual_request_count = response_dict["request_count"]
            if actual_request_count != exp_request_count:
                raise ScenarioAssertionError(
                    f"Expected request_count {exp_request_count} but got {actual_request_count}"
                )

        actual_routes_counts = [
            len(response["routes"]) for response in response_dict["responses"]
        ]
        exp_routes_counts = self._config.get("routes_count")
        if exp_routes_counts:
            if isinstance(exp_routes_counts, int):
                request_count = exp_request_count if exp_request_count else 1
                exp_routes_counts = [exp_routes_counts] * request_count
            elif isinstance(exp_routes_counts, (list, tuple)):
                if len(exp_routes_counts) != len(actual_routes_counts):
                    raise ScenarioAssertionError(
                        f"Expected {len(exp_routes_counts)} routes but got "
                        f"{len(actual_routes_counts)}")

            loop_iterator = enumerate(
                zip(exp_routes_counts, actual_routes_counts))
            for i, (exp_route_count, actual_route_count) in loop_iterator:
                if exp_route_count != actual_route_count:
                    raise ScenarioAssertionError(
                        f"Expected route count {exp_route_count} but got {actual_route_count} "
                        f"at index {i}")

        # We use a ``FrozenList`` because ``set`` (see below) doesn't accepts unhashable types
        actual_routes = FrozenList(
            FrozenList(route["path"])
            for response in response_dict["responses"]
            for route in response["routes"] if response["routes"])

        if self._config.get("distinct_routes_only", False):
            # We only want distinct routes
            actual_routes = list(set(actual_routes))
        else:
            actual_routes = list(actual_routes)

        node_address_to_index = self._runner.node_controller.address_to_index
        actual_routes_indices = [[
            node_address_to_index.get(hop, hop) for hop in actual_route
        ] for actual_route in actual_routes]

        exp_routes: List[List[Union[ChecksumAddress, int]]] = self._config.get(
            "expected_routes")
        if exp_routes:
            if len(exp_routes) != len(actual_routes):
                raise ScenarioAssertionError(
                    f"Expected {len(exp_routes)} routes but got {len(actual_routes)}."
                )
            for exp_route in exp_routes:
                exp_route_addr = [
                    self._runner.get_node_address(node) for node in exp_route
                ]
                try:
                    actual_routes.remove(exp_route_addr)
                except ValueError as ex:
                    raise ScenarioAssertionError(
                        f"Expected route {exp_route} not found. "
                        f"Actual routes: {actual_routes_indices}.") from ex

        exp_fees = self._config.get("expected_fees")
        if exp_fees:
            actual_fees = [
                route["estimated_fee"]
                for response in response_dict["responses"]
                for route in response["routes"] if response["routes"]
            ]
            if len(exp_fees) != len(actual_fees):
                raise ScenarioAssertionError(
                    f"Expected {len(exp_fees)} fees but got {len(actual_fees)}."
                )
            for i, (exp_fee,
                    actual_fee) in enumerate(zip(exp_fees, actual_fees)):
                if exp_fee != actual_fee:
                    raise ScenarioAssertionError(
                        f"Expected fee {exp_fee} but got {actual_fee} at index {i}"
                    )
        return response_dict