Example #1
0
def wait_for_newchannel(
        raiden: RaidenService,
        payment_network_id: typing.PaymentNetworkID,
        token_address: typing.TokenAddress,
        partner_address: typing.Address,
        retry_timeout: float,
) -> None:
    """Wait until the channel with partner_address is registered.

    Note:
        This does not time out, use gevent.Timeout.
    """
    channel_state = views.get_channelstate_for(
        views.state_from_raiden(raiden),
        payment_network_id,
        token_address,
        partner_address,
    )

    while channel_state is None:
        gevent.sleep(retry_timeout)
        channel_state = views.get_channelstate_for(
            views.state_from_raiden(raiden),
            payment_network_id,
            token_address,
            partner_address,
        )
Example #2
0
    def get_channel_list(
            self,
            registry_address: typing.PaymentNetworkID,
            token_address: typing.TokenAddress = None,
            partner_address: typing.Address = None,
    ) -> typing.List[NettingChannelState]:
        """Returns a list of channels associated with the optionally given
           `token_address` and/or `partner_address`.

        Args:
            token_address: an optionally provided token address
            partner_address: an optionally provided partner address

        Return:
            A list containing all channels the node participates. Optionally
            filtered by a token address and/or partner address.

        Raises:
            KeyError: An error occurred when the token address is unknown to the node.
        """
        if registry_address and not is_binary_address(registry_address):
            raise InvalidAddress('Expected binary address format for registry in get_channel_list')

        if token_address and not is_binary_address(token_address):
            raise InvalidAddress('Expected binary address format for token in get_channel_list')

        if partner_address:
            if not is_binary_address(partner_address):
                raise InvalidAddress(
                    'Expected binary address format for partner in get_channel_list',
                )
            if not token_address:
                raise UnknownTokenAddress('Provided a partner address but no token address')

        if token_address and partner_address:
            channel_state = views.get_channelstate_for(
                chain_state=views.state_from_raiden(self.raiden),
                payment_network_id=registry_address,
                token_address=token_address,
                partner_address=partner_address,
            )

            if channel_state:
                result = [channel_state]
            else:
                result = []

        elif token_address:
            result = views.list_channelstate_for_tokennetwork(
                chain_state=views.state_from_raiden(self.raiden),
                payment_network_id=registry_address,
                token_address=token_address,
            )

        else:
            result = views.list_all_channelstate(
                chain_state=views.state_from_raiden(self.raiden),
            )

        return result
Example #3
0
    def find_new_partners(self, number: int):
        """Search the token network for potential channel partners.

        Args:
            number: number of partners to return
        """
        open_channels = views.get_channelstate_open(
            chain_state=views.state_from_raiden(self.raiden),
            payment_network_id=self.registry_address,
            token_address=self.token_address,
        )
        known = set(channel_state.partner_state.address for channel_state in open_channels)
        known.add(self.BOOTSTRAP_ADDR)
        known.add(self.raiden.address)

        participants_addresses = views.get_participants_addresses(
            views.state_from_raiden(self.raiden),
            self.registry_address,
            self.token_address,
        )

        available = participants_addresses - known
        new_partners = list(available)[:number]

        log.debug('found {} partners'.format(len(available)))

        return new_partners
Example #4
0
def run_smoketests(raiden_service: RaidenService, test_config: Dict, debug: bool = False):
    """ Test that the assembled raiden_service correctly reflects the configuration from the
    smoketest_genesis. """
    try:
        chain = raiden_service.chain
        assert (
            raiden_service.default_registry.address ==
            to_canonical_address(test_config['contracts']['registry_address'])
        )
        assert (
            raiden_service.default_secret_registry.address ==
            to_canonical_address(test_config['contracts']['secret_registry_address'])
        )

        token_network_added_events = raiden_service.default_registry.filter_token_added_events()
        token_addresses = [event['args']['token_address'] for event in token_network_added_events]

        assert token_addresses == [test_config['contracts']['token_address']]

        if test_config.get('transport') == 'udp':
            assert len(chain.address_to_discovery.keys()) == 1, repr(chain.address_to_discovery)
            assert (
                list(chain.address_to_discovery.keys())[0] ==
                to_canonical_address(test_config['contracts']['discovery_address'])
            )
            discovery = list(chain.address_to_discovery.values())[0]
            assert discovery.endpoint_by_address(raiden_service.address) != TEST_ENDPOINT

        token_networks = views.get_token_network_addresses_for(
            views.state_from_raiden(raiden_service),
            raiden_service.default_registry.address,
        )
        assert len(token_networks) == 1

        channel_state = views.get_channelstate_for(
            views.state_from_raiden(raiden_service),
            raiden_service.default_registry.address,
            token_networks[0],
            unhexlify(TEST_PARTNER_ADDRESS),
        )

        distributable = channel.get_distributable(
            channel_state.our_state,
            channel_state.partner_state,
        )
        assert distributable == TEST_DEPOSIT_AMOUNT
        assert distributable == channel_state.our_state.contract_balance
        assert channel.get_status(channel_state) == CHANNEL_STATE_OPENED

        # Run API test
        run_restapi_smoketests()
    except Exception:
        error = traceback.format_exc()
        if debug:
            import pdb
            pdb.post_mortem()
        return error
Example #5
0
    def channel_batch_close(
            self,
            registry_address: typing.PaymentNetworkID,
            token_address: typing.TokenAddress,
            partner_addresses: typing.List[typing.Address],
            retry_timeout: typing.NetworkTimeout = DEFAULT_RETRY_TIMEOUT,
    ):
        """Close a channel opened with `partner_address` for the given
        `token_address`.

        Race condition, this can fail if channel was closed externally.
        """

        if not is_binary_address(token_address):
            raise InvalidAddress('Expected binary address format for token in channel close')

        if not all(map(is_binary_address, partner_addresses)):
            raise InvalidAddress('Expected binary address format for partner in channel close')

        valid_tokens = views.get_token_network_addresses_for(
            chain_state=views.state_from_raiden(self.raiden),
            payment_network_id=registry_address,
        )
        if token_address not in valid_tokens:
            raise UnknownTokenAddress('Token address is not known.')

        chain_state = views.state_from_raiden(self.raiden)
        channels_to_close = views.filter_channels_by_partneraddress(
            chain_state=chain_state,
            payment_network_id=registry_address,
            token_address=token_address,
            partner_addresses=partner_addresses,
        )
        token_network_identifier = views.get_token_network_identifier_by_token_address(
            chain_state=views.state_from_raiden(self.raiden),
            payment_network_id=registry_address,
            token_address=token_address,
        )

        for channel_state in channels_to_close:
            channel_close = ActionChannelClose(
                token_network_identifier=token_network_identifier,
                channel_identifier=channel_state.identifier,
            )

            self.raiden.handle_state_change(channel_close)

        channel_ids = [channel_state.identifier for channel_state in channels_to_close]

        waiting.wait_for_close(
            raiden=self.raiden,
            payment_network_id=registry_address,
            token_address=token_address,
            channel_ids=channel_ids,
            retry_timeout=retry_timeout,
        )
Example #6
0
    def leave(self, registry_address, only_receiving=True):
        """ Leave the token network.

        This implies closing all channels and waiting for all channels to be
        settled.

        Note: By default we're just discarding all channels for which we haven't
        received anything.  This potentially leaves deposits locked in channels after
        `closing`. This is "safe" from an accounting point of view (deposits
        can not be lost), but may still be undesirable from a liquidity point
        of view (deposits will only be freed after manually closing or after
        the partner closed the channel).

        If only_receiving is False then we close and settle all channels
        irrespective of them having received transfers or not.
        """
        with self.lock:
            self.initial_channel_target = 0

            if only_receiving:
                channels_to_close = views.get_channelstate_for_receiving(
                    views.state_from_raiden(self.raiden),
                    registry_address,
                    self.token_address,
                )
            else:
                channels_to_close = views.get_channelstate_open(
                    chain_state=views.state_from_raiden(self.raiden),
                    payment_network_id=registry_address,
                    token_address=self.token_address,
                )

            partner_addresses = [
                channel_state.partner_state.address
                for channel_state in channels_to_close
            ]
            self.api.channel_batch_close(
                registry_address,
                self.token_address,
                partner_addresses,
            )

            channel_ids = [
                channel_state.identifier
                for channel_state in channels_to_close
            ]

            waiting.wait_for_settle(
                self.raiden,
                registry_address,
                self.token_address,
                channel_ids,
                self.raiden.alarm.sleep_time,
            )

        return channels_to_close
Example #7
0
    def get_channel_list(self, registry_address, token_address=None, partner_address=None):
        """Returns a list of channels associated with the optionally given
           `token_address` and/or `partner_address`.

        Args:
            token_address (bin): an optionally provided token address
            partner_address (bin): an optionally provided partner address

        Return:
            A list containing all channels the node participates. Optionally
            filtered by a token address and/or partner address.

        Raises:
            KeyError: An error occurred when the token address is unknown to the node.
        """

        if token_address and not is_binary_address(token_address):
            raise InvalidAddress('Expected binary address format for token in get_channel_list')

        if partner_address and not is_binary_address(partner_address):
            raise InvalidAddress('Expected binary address format for partner in get_channel_list')

        result = list()
        if token_address and partner_address:
            channel_state = views.get_channelstate_for(
                views.state_from_raiden(self.raiden),
                registry_address,
                token_address,
                partner_address,
            )

            if channel_state:
                result = [channel_state]
            else:
                result = []

        elif token_address:
            result = views.list_channelstate_for_tokennetwork(
                views.state_from_raiden(self.raiden),
                registry_address,
                token_address,
            )

        elif partner_address:
            result = views.list_channelstate_for_tokennetwork(
                views.state_from_raiden(self.raiden),
                registry_address,
                partner_address,
            )

        else:
            result = views.list_all_channelstate(
                views.state_from_raiden(self.raiden),
            )

        return result
Example #8
0
def wait_for_block(
        raiden: RaidenService,
        block_number: typing.BlockNumber,
        retry_timeout: float,
) -> None:
    current_block_number = views.block_number(
        views.state_from_raiden(raiden),
    )
    while current_block_number < block_number:
        gevent.sleep(retry_timeout)
        current_block_number = views.block_number(
            views.state_from_raiden(raiden),
        )
Example #9
0
    def transfer_async(
            self,
            registry_address: typing.PaymentNetworkID,
            token_address: typing.TokenAddress,
            amount: typing.TokenAmount,
            target: typing.Address,
            identifier: typing.PaymentID = None,
    ):

        if not isinstance(amount, int):
            raise InvalidAmount('Amount not a number')

        if amount <= 0:
            raise InvalidAmount('Amount negative')

        if not is_binary_address(token_address):
            raise InvalidAddress('token address is not valid.')

        if not is_binary_address(target):
            raise InvalidAddress('target address is not valid.')

        valid_tokens = views.get_token_network_addresses_for(
            views.state_from_raiden(self.raiden),
            registry_address,
        )
        if token_address not in valid_tokens:
            raise UnknownTokenAddress('Token address is not known.')

        log.debug(
            'Initiating transfer',
            initiator=pex(self.raiden.address),
            target=pex(target),
            token=pex(token_address),
            amount=amount,
            identifier=identifier,
        )

        payment_network_identifier = self.raiden.default_registry.address
        token_network_identifier = views.get_token_network_identifier_by_token_address(
            chain_state=views.state_from_raiden(self.raiden),
            payment_network_id=payment_network_identifier,
            token_address=token_address,
        )
        async_result = self.raiden.mediated_transfer_async(
            token_network_identifier=token_network_identifier,
            amount=amount,
            target=target,
            identifier=identifier,
        )
        return async_result
Example #10
0
def handle_message_refundtransfer(raiden: RaidenService, message: RefundTransfer):
    token_network_address = message.token_network_address
    from_transfer = lockedtransfersigned_from_message(message)
    chain_state = views.state_from_raiden(raiden)

    routes = get_best_routes(
        chain_state,
        token_network_address,
        raiden.address,
        from_transfer.target,
        from_transfer.lock.amount,
        message.sender,
    )

    role = views.get_transfer_role(
        chain_state,
        from_transfer.lock.secrethash,
    )

    if role == 'initiator':
        secret = random_secret()
        state_change = ReceiveTransferRefundCancelRoute(
            message.sender,
            routes,
            from_transfer,
            secret,
        )
    else:
        state_change = ReceiveTransferRefund(
            message.sender,
            from_transfer,
            routes,
        )

    raiden.handle_state_change(state_change)
Example #11
0
 def get_tokens_list(self, registry_address):
     """Returns a list of tokens the node knows about"""
     tokens_list = views.get_token_network_addresses_for(
         views.state_from_raiden(self.raiden),
         registry_address,
     )
     return tokens_list
Example #12
0
    def token_network_connect(
            self,
            registry_address,
            token_address,
            funds,
            initial_channel_target=3,
            joinable_funds_target=.4,
    ):
        """Automatically maintain channels open for the given token network.

        Args:
            token_address (bin): the ERC20 token network to connect to.
            funds (int): the amount of funds that can be used by the ConnectionMananger.
            initial_channel_target (int): number of channels to open proactively.
            joinable_funds_target (float): fraction of the funds that will be used to join
                channels opened by other participants.
        """
        if not is_binary_address(token_address):
            raise InvalidAddress('token_address must be a valid address in binary')

        token_network_identifier = views.get_token_network_identifier_by_token_address(
            views.state_from_raiden(self.raiden),
            payment_network_id=registry_address,
            token_address=token_address,
        )

        connection_manager = self.raiden.connection_manager_for_token_network(
            token_network_identifier,
        )

        connection_manager.connect(
            funds,
            initial_channel_target=initial_channel_target,
            joinable_funds_target=joinable_funds_target,
        )
def handle_channel_closed(raiden, event: Event):
    token_network_identifier = event.originating_contract
    data = event.event_data
    channel_identifier = data['channel_identifier']
    transaction_hash = data['transactionHash']
    assert transaction_hash, 'A mined transaction must have the hash field'

    channel_state = views.get_channelstate_by_token_network_identifier(
        views.state_from_raiden(raiden),
        token_network_identifier,
        channel_identifier,
    )

    if channel_state:
        # The from address is included in the ChannelClosed event as the
        # closing_participant field
        channel_closed = ContractReceiveChannelClosed(
            transaction_hash=transaction_hash,
            transaction_from=data['closing_participant'],
            token_network_identifier=token_network_identifier,
            channel_identifier=channel_identifier,
            block_number=data['block_number'],
        )
        raiden.handle_state_change(channel_closed)
    else:
        # This is a channel close event of a channel we're not a participant of
        channel_closed = ContractReceiveRouteClosed(
            transaction_hash=transaction_hash,
            token_network_identifier=token_network_identifier,
            channel_identifier=channel_identifier,
            block_number=data['block_number'],
        )
        raiden.handle_state_change(channel_closed)
Example #14
0
    def __init__(self, raiden, token_network_identifier):
        chain_state = views.state_from_raiden(raiden)
        token_network_state = views.get_token_network_by_identifier(
            chain_state,
            token_network_identifier,
        )
        token_network_registry = views.get_token_network_registry_by_token_network_identifier(
            chain_state,
            token_network_identifier,
        )

        # TODO:
        # - Add timeout for transaction polling, used to overwrite the RaidenAPI
        # defaults
        # - Add a proper selection strategy (#576)
        self.funds = 0
        self.initial_channel_target = 0
        self.joinable_funds_target = 0

        self.raiden = raiden
        self.registry_address = token_network_registry.address
        self.token_network_identifier = token_network_identifier
        self.token_address = token_network_state.token_address

        self.lock = Semaphore()  #: protects self.funds and self.initial_channel_target
        self.api = RaidenAPI(raiden)
Example #15
0
def initiator_init(
        raiden,
        transfer_identifier,
        transfer_amount,
        transfer_secret,
        token_network_identifier,
        target_address,
):

    transfer_state = TransferDescriptionWithSecretState(
        transfer_identifier,
        transfer_amount,
        token_network_identifier,
        raiden.address,
        target_address,
        transfer_secret,
    )
    previous_address = None
    routes = routing.get_best_routes(
        views.state_from_raiden(raiden),
        token_network_identifier,
        raiden.address,
        target_address,
        transfer_amount,
        previous_address,
    )
    init_initiator_statechange = ActionInitInitiator(
        transfer_state,
        routes,
    )
    return init_initiator_statechange
Example #16
0
def initiator_init(
        raiden: 'RaidenService',
        transfer_identifier: PaymentID,
        transfer_amount: PaymentAmount,
        transfer_secret: Secret,
        token_network_identifier: TokenNetworkID,
        target_address: TargetAddress,
):

    msg = 'Should never end up initiating transfer with Secret 0x0'
    assert transfer_secret != constants.EMPTY_HASH, msg
    transfer_state = TransferDescriptionWithSecretState(
        raiden.default_registry.address,
        transfer_identifier,
        transfer_amount,
        token_network_identifier,
        InitiatorAddress(raiden.address),
        target_address,
        transfer_secret,
    )
    previous_address = None
    routes = routing.get_best_routes(
        chain_state=views.state_from_raiden(raiden),
        token_network_id=token_network_identifier,
        from_address=InitiatorAddress(raiden.address),
        to_address=target_address,
        amount=transfer_amount,
        previous_address=previous_address,
        config=raiden.config,
    )
    init_initiator_statechange = ActionInitInitiator(
        transfer_state,
        routes,
    )
    return init_initiator_statechange
Example #17
0
    def token_network_leave(
            self,
            registry_address: typing.PaymentNetworkID,
            token_address: typing.TokenAddress,
    ) -> typing.List[NettingChannelState]:
        """ Close all channels and wait for settlement. """
        if not is_binary_address(registry_address):
            raise InvalidAddress('registry_address must be a valid address in binary')
        if not is_binary_address(token_address):
            raise InvalidAddress('token_address must be a valid address in binary')

        if token_address not in self.get_tokens_list(registry_address):
            raise UnknownTokenAddress('token_address unknown')

        token_network_identifier = views.get_token_network_identifier_by_token_address(
            chain_state=views.state_from_raiden(self.raiden),
            payment_network_id=registry_address,
            token_address=token_address,
        )

        connection_manager = self.raiden.connection_manager_for_token_network(
            token_network_identifier,
        )

        return connection_manager.leave(registry_address)
Example #18
0
def wait_for_settle(
        raiden: RaidenService,
        payment_network_id: typing.PaymentNetworkID,
        token_address: typing.TokenAddress,
        channel_ids: typing.List[typing.ChannelID],
        retry_timeout: float,
) -> None:
    """Wait until all channels are settled.

    Note:
        This does not time out, use gevent.Timeout.
    """
    if not isinstance(channel_ids, list):
        raise ValueError('channel_ids must be a list')

    channel_ids = list(channel_ids)

    while channel_ids:
        last_id = channel_ids[-1]
        channel_state = views.get_channelstate_by_id(
            views.state_from_raiden(raiden),
            payment_network_id,
            token_address,
            last_id,
        )

        channel_is_settled = (
            channel_state is None or
            channel.get_status(channel_state) == CHANNEL_STATE_SETTLED
        )

        if channel_is_settled:
            channel_ids.pop()
        else:
            gevent.sleep(retry_timeout)
Example #19
0
    def install_all_blockchain_filters(
            self,
            token_network_registry_proxy: TokenNetworkRegistry,
            secret_registry_proxy: SecretRegistry,
            from_block: BlockNumber,
    ):
        with self.event_poll_lock:
            node_state = views.state_from_raiden(self)
            token_networks = views.get_token_network_identifiers(
                node_state,
                token_network_registry_proxy.address,
            )

            self.blockchain_events.add_token_network_registry_listener(
                token_network_registry_proxy=token_network_registry_proxy,
                contract_manager=self.contract_manager,
                from_block=from_block,
            )
            self.blockchain_events.add_secret_registry_listener(
                secret_registry_proxy=secret_registry_proxy,
                contract_manager=self.contract_manager,
                from_block=from_block,
            )

            for token_network in token_networks:
                token_network_proxy = self.chain.token_network(
                    TokenNetworkAddress(token_network),
                )
                self.blockchain_events.add_token_network_listener(
                    token_network_proxy=token_network_proxy,
                    contract_manager=self.contract_manager,
                    from_block=from_block,
                )
Example #20
0
def wait_for_close(
        raiden: RaidenService,
        payment_network_id: typing.PaymentNetworkID,
        token_address: typing.TokenAddress,
        channel_ids: typing.List[typing.ChannelID],
        retry_timeout: float,
) -> None:
    """Wait until all channels are closed.

    Note:
        This does not time out, use gevent.Timeout.
    """
    channel_ids = list(channel_ids)

    while channel_ids:
        last_id = channel_ids[-1]
        channel_state = views.get_channelstate_by_id(
            views.state_from_raiden(raiden),
            payment_network_id,
            token_address,
            last_id,
        )

        channel_is_settled = (
            channel_state is None or
            channel.get_status(channel_state) in CHANNEL_AFTER_CLOSE_STATES
        )

        if channel_is_settled:
            channel_ids.pop()
        else:
            gevent.sleep(retry_timeout)
Example #21
0
def wait_for_settle_all_channels(
        raiden: RaidenService,
        retry_timeout: float,
) -> None:
    """Wait until all channels are settled.

    Note:
        This does not time out, use gevent.Timeout.
    """
    chain_state = views.state_from_raiden(raiden)

    id_paymentnetworkstate = chain_state.identifiers_to_paymentnetworks.items()
    for payment_network_id, payment_network_state in id_paymentnetworkstate:

        id_tokennetworkstate = payment_network_state.tokenidentifiers_to_tokennetworks.items()
        for token_network_id, token_network_state in id_tokennetworkstate:
            channel_ids = token_network_state.channelidentifiers_to_channels.keys()

            wait_for_settle(
                raiden,
                payment_network_id,
                token_network_id,
                channel_ids,
                retry_timeout,
            )
Example #22
0
 def get_tokens_list(self, registry_address: typing.PaymentNetworkID):
     """Returns a list of tokens the node knows about"""
     tokens_list = views.get_token_network_addresses_for(
         chain_state=views.state_from_raiden(self.raiden),
         payment_network_id=registry_address,
     )
     return tokens_list
Example #23
0
 def __repr__(self) -> str:
     open_channels = views.get_channelstate_open(
         chain_state=views.state_from_raiden(self.raiden),
         payment_network_id=self.registry_address,
         token_address=self.token_address,
     )
     return f'{self.__class__.__name__}(target={self.initial_channel_target} ' +\
         f'channels={len(open_channels)}:{open_channels!r})'
Example #24
0
def wait_for_payment_network(
        raiden: RaidenService,
        payment_network_id: typing.PaymentNetworkID,
        token_address: typing.TokenAddress,
        retry_timeout: float,
) -> None:
    token_network = views.get_token_network_by_token_address(
        views.state_from_raiden(raiden),
        payment_network_id,
        token_address,
    )
    while token_network is None:
        gevent.sleep(retry_timeout)
        token_network = views.get_token_network_by_token_address(
            views.state_from_raiden(raiden),
            payment_network_id,
            token_address,
        )
Example #25
0
def wait_for_payment_balance(
        raiden: RaidenService,
        payment_network_id: typing.PaymentNetworkID,
        token_address: typing.TokenAddress,
        partner_address: typing.Address,
        target_address: typing.Address,
        target_balance: typing.TokenAmount,
        retry_timeout: float,
) -> None:
    """Wait until a given channels balance exceeds the target balance.

    Note:
        This does not time out, use gevent.Timeout.
    """
    def get_balance(end_state):
        if end_state.balance_proof:
            return end_state.balance_proof.transferred_amount
        else:
            return 0

    if target_address == raiden.address:
        balance = lambda channel_state: get_balance(channel_state.partner_state)
    elif target_address == partner_address:
        balance = lambda channel_state: get_balance(channel_state.our_state)
    else:
        raise ValueError('target_address must be one of the channel participants')

    channel_state = views.get_channelstate_for(
        views.state_from_raiden(raiden),
        payment_network_id,
        token_address,
        partner_address,
    )

    while balance(channel_state) < target_balance:
        log.critical('wait', b=balance(channel_state), t=target_balance)
        gevent.sleep(retry_timeout)
        channel_state = views.get_channelstate_for(
            views.state_from_raiden(raiden),
            payment_network_id,
            token_address,
            partner_address,
        )
Example #26
0
def wait_for_healthy(
        raiden: RaidenService,
        node_address: typing.Address,
        retry_timeout: float,
) -> None:
    """Wait until `node_address` becomes healthy.

    Note:
        This does not time out, use gevent.Timeout.
    """
    network_statuses = views.get_networkstatuses(
        views.state_from_raiden(raiden),
    )

    while network_statuses.get(node_address) != NODE_NETWORK_REACHABLE:
        gevent.sleep(retry_timeout)
        network_statuses = views.get_networkstatuses(
            views.state_from_raiden(raiden),
        )
Example #27
0
def log_open_channels(raiden, registry_address, token_address, funds):
    chain_state = views.state_from_raiden(raiden)
    open_channels = views.get_channelstate_open(
        chain_state=chain_state,
        payment_network_id=registry_address,
        token_address=token_address,
    )

    if open_channels:
        sum_deposits = views.get_our_capacity_for_token_network(
            views.state_from_raiden(raiden),
            registry_address,
            token_address,
        )
        log.debug(
            'connect() called on an already joined token network',
            registry_address=pex(registry_address),
            token_address=pex(token_address),
            open_channels=len(open_channels),
            sum_deposits=sum_deposits,
            funds=funds,
        )
def handle_channel_new_balance(raiden, event: Event):
    data = event.event_data
    channel_identifier = data['channel_identifier']
    token_network_identifier = event.originating_contract
    participant_address = data['participant']
    total_deposit = data['args']['total_deposit']
    deposit_block_number = data['block_number']
    transaction_hash = data['transactionHash']
    assert transaction_hash, 'A mined transaction must have the hash field'

    previous_channel_state = views.get_channelstate_by_token_network_identifier(
        views.state_from_raiden(raiden),
        token_network_identifier,
        channel_identifier,
    )

    # Channels will only be registered if this node is a participant
    is_participant = previous_channel_state is not None

    if is_participant:
        previous_balance = previous_channel_state.our_state.contract_balance
        balance_was_zero = previous_balance == 0

        deposit_transaction = TransactionChannelNewBalance(
            participant_address,
            total_deposit,
            deposit_block_number,
        )

        newbalance_statechange = ContractReceiveChannelNewBalance(
            transaction_hash=transaction_hash,
            token_network_identifier=token_network_identifier,
            channel_identifier=channel_identifier,
            deposit_transaction=deposit_transaction,
            block_number=data['block_number'],
        )
        raiden.handle_state_change(newbalance_statechange)

        if balance_was_zero and participant_address != raiden.address:
            connection_manager = raiden.connection_manager_for_token_network(
                token_network_identifier,
            )

            join_channel = gevent.spawn(
                connection_manager.join_channel,
                participant_address,
                total_deposit,
            )

            raiden.add_pending_greenlet(join_channel)
Example #29
0
    def token_network_connect(
            self,
            registry_address: typing.PaymentNetworkID,
            token_address: typing.TokenAddress,
            funds: typing.TokenAmount,
            initial_channel_target: int = 3,
            joinable_funds_target: float = 0.4,
    ) -> None:
        """ Automatically maintain channels open for the given token network.

        Args:
            token_address: the ERC20 token network to connect to.
            funds: the amount of funds that can be used by the ConnectionMananger.
            initial_channel_target: number of channels to open proactively.
            joinable_funds_target: fraction of the funds that will be used to join
                channels opened by other participants.
        """
        if not is_binary_address(registry_address):
            raise InvalidAddress('registry_address must be a valid address in binary')
        if not is_binary_address(token_address):
            raise InvalidAddress('token_address must be a valid address in binary')

        token_network_identifier = views.get_token_network_identifier_by_token_address(
            chain_state=views.state_from_raiden(self.raiden),
            payment_network_id=registry_address,
            token_address=token_address,
        )

        connection_manager = self.raiden.connection_manager_for_token_network(
            token_network_identifier,
        )

        has_enough_reserve, estimated_required_reserve = has_enough_gas_reserve(
            raiden=self.raiden,
            channels_to_open=initial_channel_target,
        )

        if not has_enough_reserve:
            raise InsufficientGasReserve((
                'The account balance is below the estimated amount necessary to '
                'finish the lifecycles of all active channels. A balance of at '
                f'least {estimated_required_reserve} wei is required.'
            ))

        connection_manager.connect(
            funds=funds,
            initial_channel_target=initial_channel_target,
            joinable_funds_target=joinable_funds_target,
        )
Example #30
0
def wait_for_participant_newbalance(
        raiden: RaidenService,
        payment_network_id: typing.PaymentNetworkID,
        token_address: typing.TokenAddress,
        partner_address: typing.Address,
        target_address: typing.Address,
        target_balance: typing.TokenAmount,
        retry_timeout: float,
) -> None:
    """Wait until a given channels balance exceeds the target balance.

    Note:
        This does not time out, use gevent.Timeout.
    """
    if target_address == raiden.address:
        balance = lambda channel_state: channel_state.our_state.contract_balance
    elif target_address == partner_address:
        balance = lambda channel_state: channel_state.partner_state.contract_balance
    else:
        raise ValueError('target_address must be one of the channel participants')

    channel_state = views.get_channelstate_for(
        views.state_from_raiden(raiden),
        payment_network_id,
        token_address,
        partner_address,
    )

    while balance(channel_state) < target_balance:
        gevent.sleep(retry_timeout)
        channel_state = views.get_channelstate_for(
            views.state_from_raiden(raiden),
            payment_network_id,
            token_address,
            partner_address,
        )
Example #31
0
 def _queueids_to_queues(self) -> QueueIdsToQueues:
     chain_state = views.state_from_raiden(self._raiden_service)
     return views.get_all_messagequeues(chain_state)
Example #32
0
def run_test_refund_transfer(
    raiden_chain, number_of_nodes, token_addresses, deposit, network_wait, retry_timeout
):
    """A failed transfer must send a refund back.

    TODO:
        - Unlock the token on refund #1091
        - Clear the merkletree and update the locked amount #193
        - Remove the refund message type #490"""
    # Topology:
    #
    #  0 -> 1 -> 2
    #
    app0, app1, app2 = raiden_chain
    token_address = token_addresses[0]
    payment_network_identifier = app0.raiden.default_registry.address
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0), payment_network_identifier, token_address
    )

    # make a transfer to test the path app0 -> app1 -> app2
    identifier_path = 1
    amount_path = 1
    transfer(
        initiator_app=app0,
        target_app=app2,
        token_address=token_address,
        amount=amount_path,
        identifier=identifier_path,
        timeout=network_wait * number_of_nodes,
    )

    # drain the channel app1 -> app2
    identifier_drain = 2
    amount_drain = deposit * 8 // 10
    transfer(
        initiator_app=app1,
        target_app=app2,
        token_address=token_address,
        amount=amount_drain,
        identifier=identifier_drain,
        timeout=network_wait,
    )

    # wait for the nodes to sync
    gevent.sleep(1)

    with gevent.Timeout(network_wait):
        wait_assert(
            assert_synced_channel_state,
            token_network_identifier,
            app0,
            deposit - amount_path,
            [],
            app1,
            deposit + amount_path,
            [],
        )
    with gevent.Timeout(network_wait):
        wait_assert(
            assert_synced_channel_state,
            token_network_identifier,
            app1,
            deposit - amount_path - amount_drain,
            [],
            app2,
            deposit + amount_path + amount_drain,
            [],
        )

    # app0 -> app1 -> app2 is the only available path, but the channel app1 ->
    # app2 doesn't have capacity, so a refund will be sent on app1 -> app0
    identifier_refund = 3
    amount_refund = 50
    payment_status = app0.raiden.mediated_transfer_async(
        token_network_identifier, amount_refund, app2.raiden.address, identifier_refund,
        payment_hash_invoice=EMPTY_PAYMENT_HASH_INVOICE
    )
    msg = "there is no path with capacity, the transfer must fail"
    assert payment_status.payment_done.wait() is False, msg

    gevent.sleep(0.2)

    # A lock structure with the correct amount

    send_locked = raiden_events_search_for_item(
        app0.raiden, SendLockedTransfer, {"transfer": {"lock": {"amount": amount_refund}}}
    )
    assert send_locked
    secrethash = send_locked.transfer.lock.secrethash

    send_refund = raiden_events_search_for_item(app1.raiden, SendRefundTransfer, {})
    assert send_refund

    lock = send_locked.transfer.lock
    refund_lock = send_refund.transfer.lock
    assert lock.amount == refund_lock.amount
    assert lock.secrethash
    assert lock.expiration
    assert lock.secrethash == refund_lock.secrethash

    # Both channels have the amount locked because of the refund message
    with gevent.Timeout(network_wait):
        wait_assert(
            assert_synced_channel_state,
            token_network_identifier,
            app0,
            deposit - amount_path,
            [lock],
            app1,
            deposit + amount_path,
            [refund_lock],
        )
    with gevent.Timeout(network_wait):
        wait_assert(
            assert_synced_channel_state,
            token_network_identifier,
            app1,
            deposit - amount_path - amount_drain,
            [],
            app2,
            deposit + amount_path + amount_drain,
            [],
        )

    # Additional checks for LockExpired causing nonce mismatch after refund transfer:
    # https://github.com/raiden-network/raiden/issues/3146#issuecomment-447378046
    # At this point make sure that the initiator has not deleted the payment task
    assert secrethash in state_from_raiden(app0.raiden).payment_mapping.secrethashes_to_task

    # Wait for lock lock expiration but make sure app0 never processes LockExpired
    with dont_handle_lock_expired_mock(app0):
        wait_for_block(
            raiden=app0.raiden,
            block_number=channel.get_sender_expiration_threshold(lock) + 1,
            retry_timeout=retry_timeout,
        )
        # make sure that app0 still has the payment task for the secrethash
        # https://github.com/raiden-network/raiden/issues/3183
        assert secrethash in state_from_raiden(app0.raiden).payment_mapping.secrethashes_to_task

        # make sure that app1 sent a lock expired message for the secrethash
        send_lock_expired = raiden_events_search_for_item(
            app1.raiden, SendLockExpired, {"secrethash": secrethash}
        )
        assert send_lock_expired
        # make sure that app0 never got it
        state_changes = app0.raiden.wal.storage.get_statechanges_by_identifier(0, "latest")
        assert not search_for_item(state_changes, ReceiveLockExpired, {"secrethash": secrethash})

    # Out of the handicapped app0 transport.
    # Now wait till app0 receives and processes LockExpired
    receive_lock_expired = wait_for_state_change(
        app0.raiden, ReceiveLockExpired, {"secrethash": secrethash}, retry_timeout
    )
    # And also till app1 received the processed
    wait_for_state_change(
        app1.raiden,
        ReceiveProcessed,
        {"message_identifier": receive_lock_expired.message_identifier},
        retry_timeout,
    )

    # make sure app1 queue has cleared the SendLockExpired
    chain_state1 = views.state_from_app(app1)
    queues1 = views.get_all_messagequeues(chain_state=chain_state1)
    result = [
        (queue_id, queue)
        for queue_id, queue in queues1.items()
        if queue_id.recipient == app0.raiden.address and queue
    ]
    assert not result

    # and now wait for 1 more block so that the payment task can be deleted
    wait_for_block(
        raiden=app0.raiden,
        block_number=app0.raiden.get_block_number() + 1,
        retry_timeout=retry_timeout,
    )

    # and since the lock expired message has been sent and processed then the
    # payment task should have been deleted from both nodes
    # https://github.com/raiden-network/raiden/issues/3183
    assert secrethash not in state_from_raiden(app0.raiden).payment_mapping.secrethashes_to_task
    assert secrethash not in state_from_raiden(app1.raiden).payment_mapping.secrethashes_to_task
Example #33
0
def run_test_different_view_of_last_bp_during_unlock(
    raiden_chain,
    number_of_nodes,
    token_addresses,
    deposit,
    network_wait,
    retry_timeout,
    blockchain_type,
):
    """Test for https://github.com/raiden-network/raiden/issues/3196#issuecomment-449163888"""
    # Topology:
    #
    #  0 -> 1 -> 2
    #
    app0, app1, app2 = raiden_chain
    token_address = token_addresses[0]
    payment_network_identifier = app0.raiden.default_registry.address
    token_network_identifier = views.get_token_network_identifier_by_token_address(
        views.state_from_app(app0), payment_network_identifier, token_address
    )
    token_proxy = app0.raiden.chain.token(token_address)
    initial_balance0 = token_proxy.balance_of(app0.raiden.address)
    initial_balance1 = token_proxy.balance_of(app1.raiden.address)

    # make a transfer to test the path app0 -> app1 -> app2
    identifier_path = 1
    amount_path = 1
    transfer(
        initiator_app=app0,
        target_app=app2,
        token_address=token_address,
        amount=amount_path,
        identifier=identifier_path,
        timeout=network_wait * number_of_nodes,
    )

    # drain the channel app1 -> app2
    identifier_drain = 2
    amount_drain = deposit * 8 // 10
    transfer(
        initiator_app=app1,
        target_app=app2,
        token_address=token_address,
        amount=amount_drain,
        identifier=identifier_drain,
        timeout=network_wait,
    )

    with gevent.Timeout(network_wait):
        wait_assert(
            assert_synced_channel_state,
            token_network_identifier,
            app0,
            deposit - amount_path,
            [],
            app1,
            deposit + amount_path,
            [],
        )
    with gevent.Timeout(network_wait):
        wait_assert(
            assert_synced_channel_state,
            token_network_identifier,
            app1,
            deposit - amount_path - amount_drain,
            [],
            app2,
            deposit + amount_path + amount_drain,
            [],
        )

    # app0 -> app1 -> app2 is the only available path, but the channel app1 ->
    # app2 doesn't have capacity, so a refund will be sent on app1 -> app0
    identifier_refund = 3
    amount_refund = 50
    payment_status = app0.raiden.mediated_transfer_async(
        token_network_identifier, amount_refund, app2.raiden.address, identifier_refund,
        payment_hash_invoice=EMPTY_PAYMENT_HASH_INVOICE
    )
    msg = "there is no path with capacity, the transfer must fail"
    assert payment_status.payment_done.wait() is False, msg

    gevent.sleep(0.2)

    # A lock structure with the correct amount

    send_locked = raiden_events_search_for_item(
        app0.raiden, SendLockedTransfer, {"transfer": {"lock": {"amount": amount_refund}}}
    )
    assert send_locked
    secrethash = send_locked.transfer.lock.secrethash

    send_refund = raiden_events_search_for_item(app1.raiden, SendRefundTransfer, {})
    assert send_refund

    lock = send_locked.transfer.lock
    refund_lock = send_refund.transfer.lock
    assert lock.amount == refund_lock.amount
    assert lock.secrethash
    assert lock.expiration
    assert lock.secrethash == refund_lock.secrethash

    # Both channels have the amount locked because of the refund message
    with gevent.Timeout(network_wait):
        wait_assert(
            assert_synced_channel_state,
            token_network_identifier,
            app0,
            deposit - amount_path,
            [lock],
            app1,
            deposit + amount_path,
            [refund_lock],
        )
    with gevent.Timeout(network_wait):
        wait_assert(
            assert_synced_channel_state,
            token_network_identifier,
            app1,
            deposit - amount_path - amount_drain,
            [],
            app2,
            deposit + amount_path + amount_drain,
            [],
        )

    # Additional checks for LockExpired causing nonce mismatch after refund transfer:
    # https://github.com/raiden-network/raiden/issues/3146#issuecomment-447378046
    # At this point make sure that the initiator has not deleted the payment task
    assert secrethash in state_from_raiden(app0.raiden).payment_mapping.secrethashes_to_task

    with dont_handle_node_change_network_state():
        # now app1 goes offline
        app1.raiden.stop()
        app1.raiden.get()
        assert not app1.raiden

        # Wait for lock expiration so that app0 sends a LockExpired
        wait_for_block(
            raiden=app0.raiden,
            block_number=channel.get_sender_expiration_threshold(lock) + 1,
            retry_timeout=retry_timeout,
        )

        # make sure that app0 sent a lock expired message for the secrethash
        wait_for_raiden_event(
            app0.raiden, SendLockExpired, {"secrethash": secrethash}, retry_timeout
        )

        # now app0 closes the channel
        RaidenAPI(app0.raiden).channel_close(
            registry_address=payment_network_identifier,
            token_address=token_address,
            partner_address=app1.raiden.address,
        )

    count = 0
    original_update = app1.raiden.raiden_event_handler.handle_contract_send_channelupdate

    def patched_update(raiden, event):
        nonlocal count
        count += 1
        original_update(raiden, event)

    app1.raiden.raiden_event_handler.handle_contract_send_channelupdate = patched_update
    # and now app1 comes back online
    app1.raiden.start()
    # test for https://github.com/raiden-network/raiden/issues/3216
    assert count == 1, "Update transfer should have only been called once during restart"
    channel_identifier = get_channelstate(app0, app1, token_network_identifier).identifier

    # and we wait for settlement
    wait_for_settle(
        raiden=app0.raiden,
        payment_network_id=payment_network_identifier,
        token_address=token_address,
        channel_ids=[channel_identifier],
        retry_timeout=app0.raiden.alarm.sleep_time,
    )

    timeout = 30 if blockchain_type == "parity" else 10
    with gevent.Timeout(timeout):
        unlock_app0 = wait_for_state_change(
            app0.raiden,
            ContractReceiveChannelBatchUnlock,
            {"participant": app0.raiden.address},
            retry_timeout,
        )
    assert unlock_app0.returned_tokens == 50
    with gevent.Timeout(timeout):
        unlock_app1 = wait_for_state_change(
            app1.raiden,
            ContractReceiveChannelBatchUnlock,
            {"participant": app1.raiden.address},
            retry_timeout,
        )
    assert unlock_app1.returned_tokens == 50
    final_balance0 = token_proxy.balance_of(app0.raiden.address)
    final_balance1 = token_proxy.balance_of(app1.raiden.address)

    assert final_balance0 - deposit - initial_balance0 == -1
    assert final_balance1 - deposit - initial_balance1 == 1
Example #34
0
def run_smoketest(print_step: Callable, setup: RaidenTestSetup) -> None:
    print_step("Starting Raiden")

    app = None
    try:
        app = run_app(**setup.args)
        raiden_api = app.raiden.raiden_api
        assert raiden_api is not None  # for mypy

        block = BlockNumber(app.raiden.get_block_number() +
                            DEFAULT_NUMBER_OF_BLOCK_CONFIRMATIONS)
        # Proxies now use the confirmed block hash to query the chain for
        # prerequisite checks. Wait a bit here to make sure that the confirmed
        # block hash contains the deployed token network or else things break
        wait_for_block(raiden=app.raiden,
                       block_number=block,
                       retry_timeout=1.0)

        raiden_api.channel_open(
            registry_address=TokenNetworkRegistryAddress(
                setup.contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY]),
            token_address=TokenAddress(
                to_canonical_address(setup.token.address)),
            partner_address=ConnectionManager.BOOTSTRAP_ADDR,
        )
        raiden_api.set_total_channel_deposit(
            registry_address=TokenNetworkRegistryAddress(
                setup.contract_addresses[CONTRACT_TOKEN_NETWORK_REGISTRY]),
            token_address=TokenAddress(
                to_canonical_address(setup.token.address)),
            partner_address=ConnectionManager.BOOTSTRAP_ADDR,
            total_deposit=TEST_DEPOSIT_AMOUNT,
        )
        token_addresses = [to_checksum_address(setup.token.address)
                           ]  # type: ignore

        print_step("Running smoketest")

        raiden_service = app.raiden
        token_network_added_events = raiden_service.default_registry.filter_token_added_events(
        )
        events_token_addresses = [
            event["args"]["token_address"]
            for event in token_network_added_events
        ]

        assert events_token_addresses == token_addresses

        token_networks = views.get_token_identifiers(
            views.state_from_raiden(raiden_service),
            raiden_service.default_registry.address)
        assert len(token_networks) == 1

        channel_state = views.get_channelstate_for(
            chain_state=views.state_from_raiden(raiden_service),
            token_network_registry_address=raiden_service.default_registry.
            address,
            token_address=token_networks[0],
            partner_address=ConnectionManager.BOOTSTRAP_ADDR,
        )
        assert channel_state

        distributable = channel.get_distributable(channel_state.our_state,
                                                  channel_state.partner_state)
        assert distributable == TEST_DEPOSIT_AMOUNT
        assert Balance(
            distributable) == channel_state.our_state.contract_balance
        assert channel.get_status(channel_state) == ChannelState.STATE_OPENED

        port_number = raiden_service.config.rest_api.port
        response = requests.get(
            f"http://localhost:{port_number}/api/v1/channels")

        assert response.status_code == HTTPStatus.OK

        response_json = json.loads(response.content)
        assert response_json[0]["partner_address"] == to_checksum_address(
            ConnectionManager.BOOTSTRAP_ADDR)
        assert response_json[0]["state"] == "opened"
        assert int(response_json[0]["balance"]) > 0
    finally:
        if app is not None:
            app.stop()
            app.raiden.greenlet.get()
Example #35
0
    def channel_open(
        self,
        registry_address: TokenNetworkRegistryAddress,
        token_address: TokenAddress,
        partner_address: Address,
        settle_timeout: BlockTimeout = None,
        reveal_timeout: BlockTimeout = None,
        retry_timeout: NetworkTimeout = DEFAULT_RETRY_TIMEOUT,
    ) -> ChannelID:
        """ Open a channel with the peer at `partner_address`
        with the given `token_address`.
        """
        if settle_timeout is None:
            settle_timeout = self.raiden.config.settle_timeout

        if reveal_timeout is None:
            reveal_timeout = self.raiden.config.reveal_timeout

        if reveal_timeout <= 0:
            raise InvalidRevealTimeout(
                "reveal_timeout should be larger than zero")

        if settle_timeout < reveal_timeout * 2:
            raise InvalidSettleTimeout(
                "`settle_timeout` can not be smaller than double the "
                "`reveal_timeout`.\n "
                "\n "
                "The setting `reveal_timeout` determines the maximum number of "
                "blocks it should take a transaction to be mined when the "
                "blockchain is under congestion. This setting determines the "
                "when a node must go on-chain to register a secret, and it is "
                "therefore the lower bound of the lock expiration. The "
                "`settle_timeout` determines when a channel can be settled "
                "on-chain, for this operation to be safe all locks must have "
                "been resolved, for this reason the `settle_timeout` has to be "
                "larger than `reveal_timeout`.")

        if not is_binary_address(registry_address):
            raise InvalidBinaryAddress(
                "Expected binary address format for registry in channel open")

        if not is_binary_address(token_address):
            raise InvalidBinaryAddress(
                "Expected binary address format for token in channel open")

        if not is_binary_address(partner_address):
            raise InvalidBinaryAddress(
                "Expected binary address format for partner in channel open")

        confirmed_block_identifier = views.get_confirmed_blockhash(self.raiden)
        registry = self.raiden.proxy_manager.token_network_registry(
            registry_address, block_identifier=confirmed_block_identifier)

        settlement_timeout_min = registry.settlement_timeout_min(
            block_identifier=confirmed_block_identifier)
        settlement_timeout_max = registry.settlement_timeout_max(
            block_identifier=confirmed_block_identifier)

        if settle_timeout < settlement_timeout_min:
            raise InvalidSettleTimeout(
                f"Settlement timeout should be at least {settlement_timeout_min}"
            )

        if settle_timeout > settlement_timeout_max:
            raise InvalidSettleTimeout(
                f"Settlement timeout exceeds max of {settlement_timeout_max}")

        token_network_address = registry.get_token_network(
            token_address=token_address,
            block_identifier=confirmed_block_identifier)
        if token_network_address is None:
            raise TokenNotRegistered(
                "Token network for token %s does not exist" %
                to_checksum_address(token_address))

        token_network = self.raiden.proxy_manager.token_network(
            address=token_network_address,
            block_identifier=confirmed_block_identifier)

        safety_deprecation_switch = token_network.safety_deprecation_switch(
            block_identifier=confirmed_block_identifier)

        if safety_deprecation_switch:
            msg = (
                "This token_network has been deprecated. New channels cannot be "
                "open for this network, usage of the newly deployed token "
                "network contract is highly encouraged.")
            raise TokenNetworkDeprecated(msg)

        duplicated_channel = self.is_already_existing_channel(
            token_network_address=token_network_address,
            partner_address=partner_address,
            block_identifier=confirmed_block_identifier,
        )
        if duplicated_channel:
            raise DuplicatedChannelError(
                f"A channel with {to_checksum_address(partner_address)} for token "
                f"{to_checksum_address(token_address)} already exists. "
                f"(At blockhash: {confirmed_block_identifier.hex()})")

        has_enough_reserve, estimated_required_reserve = has_enough_gas_reserve(
            self.raiden, channels_to_open=1)

        if not has_enough_reserve:
            raise InsufficientGasReserve(
                "The account balance is below the estimated amount necessary to "
                "finish the lifecycles of all active channels. A balance of at "
                f"least {estimated_required_reserve} wei is required.")

        try:
            token_network.new_netting_channel(
                partner=partner_address,
                settle_timeout=settle_timeout,
                given_block_identifier=confirmed_block_identifier,
            )
        except DuplicatedChannelError:
            log.info("partner opened channel first")
        except RaidenRecoverableError:
            # The channel may have been created in the pending block.
            duplicated_channel = self.is_already_existing_channel(
                token_network_address=token_network_address,
                partner_address=partner_address)
            if duplicated_channel:
                log.info("Channel has already been opened")
            else:
                raise

        waiting.wait_for_newchannel(
            raiden=self.raiden,
            token_network_registry_address=registry_address,
            token_address=token_address,
            partner_address=partner_address,
            retry_timeout=retry_timeout,
        )

        chain_state = views.state_from_raiden(self.raiden)
        channel_state = views.get_channelstate_for(
            chain_state=chain_state,
            token_network_registry_address=registry_address,
            token_address=token_address,
            partner_address=partner_address,
        )

        assert channel_state, f"channel {channel_state} is gone"

        self.raiden.set_channel_reveal_timeout(
            canonical_identifier=channel_state.canonical_identifier,
            reveal_timeout=reveal_timeout)

        return channel_state.identifier
Example #36
0
    def start(self):
        """ Start the node synchronously. Raises directly if anything went wrong on startup """
        if not self.stop_event.ready():
            raise RuntimeError(f'{self!r} already started')
        self.stop_event.clear()

        if self.database_dir is not None:
            self.db_lock.acquire(timeout=0)
            assert self.db_lock.is_locked

        # start the registration early to speed up the start
        if self.config['transport_type'] == 'udp':
            endpoint_registration_greenlet = gevent.spawn(
                self.discovery.register,
                self.address,
                self.config['transport']['udp']['external_ip'],
                self.config['transport']['udp']['external_port'],
            )

        storage = sqlite.SQLiteStorage(self.database_path, serialize.JSONSerializer())
        self.wal = wal.restore_to_state_change(
            transition_function=node.state_transition,
            storage=storage,
            state_change_identifier='latest',
        )

        if self.wal.state_manager.current_state is None:
            log.debug(
                'No recoverable state available, created inital state',
                node=pex(self.address),
            )
            # On first run Raiden needs to fetch all events for the payment
            # network, to reconstruct all token network graphs and find opened
            # channels
            last_log_block_number = self.query_start_block

            state_change = ActionInitChain(
                random.Random(),
                last_log_block_number,
                self.chain.node_address,
                self.chain.network_id,
            )
            self.handle_state_change(state_change)

            payment_network = PaymentNetworkState(
                self.default_registry.address,
                [],  # empty list of token network states as it's the node's startup
            )
            state_change = ContractReceiveNewPaymentNetwork(
                constants.EMPTY_HASH,
                payment_network,
                last_log_block_number,
            )
            self.handle_state_change(state_change)
        else:
            # The `Block` state change is dispatched only after all the events
            # for that given block have been processed, filters can be safely
            # installed starting from this position without losing events.
            last_log_block_number = views.block_number(self.wal.state_manager.current_state)
            log.debug(
                'Restored state from WAL',
                last_restored_block=last_log_block_number,
                node=pex(self.address),
            )

            known_networks = views.get_payment_network_identifiers(views.state_from_raiden(self))
            if known_networks and self.default_registry.address not in known_networks:
                configured_registry = pex(self.default_registry.address)
                known_registries = lpex(known_networks)
                raise RuntimeError(
                    f'Token network address mismatch.\n'
                    f'Raiden is configured to use the smart contract '
                    f'{configured_registry}, which conflicts with the current known '
                    f'smart contracts {known_registries}',
                )

        # Restore the current snapshot group
        state_change_qty = self.wal.storage.count_state_changes()
        self.snapshot_group = state_change_qty // SNAPSHOT_STATE_CHANGES_COUNT

        # Install the filters using the correct from_block value, otherwise
        # blockchain logs can be lost.
        self.install_all_blockchain_filters(
            self.default_registry,
            self.default_secret_registry,
            last_log_block_number,
        )

        # Complete the first_run of the alarm task and synchronize with the
        # blockchain since the last run.
        #
        # Notes about setup order:
        # - The filters must be polled after the node state has been primed,
        # otherwise the state changes won't have effect.
        # - The alarm must complete its first run before the transport is started,
        #   to reject messages for closed/settled channels.
        self.alarm.register_callback(self._callback_new_block)
        self.alarm.first_run(last_log_block_number)

        chain_state = views.state_from_raiden(self)

        self._initialize_transactions_queues(chain_state)
        self._initialize_whitelists(chain_state)

        # send messages in queue before starting transport,
        # this is necessary to avoid a race where, if the transport is started
        # before the messages are queued, actions triggered by it can cause new
        # messages to be enqueued before these older ones
        self._initialize_messages_queues(chain_state)

        # The transport must not ever be started before the alarm task's
        # `first_run()` has been, because it's this method which synchronizes the
        # node with the blockchain, including the channel's state (if the channel
        # is closed on-chain new messages must be rejected, which will not be the
        # case if the node is not synchronized)
        self.transport.start(self, self.message_handler)

        # First run has been called above!
        self.alarm.start()

        # exceptions on these subtasks should crash the app and bubble up
        self.alarm.link_exception(self.on_error)
        self.transport.link_exception(self.on_error)

        # Health check needs the transport layer
        self.start_neighbours_healthcheck(chain_state)

        if self.config['transport_type'] == 'udp':
            endpoint_registration_greenlet.get()  # re-raise if exception occurred

        log.debug('Raiden Service started', node=pex(self.address))
        super().start()
    def handle_contract_send_channelunlock(
        raiden: 'RaidenService',
        channel_unlock_event: ContractSendChannelBatchUnlock,
    ):
        token_network_identifier = channel_unlock_event.token_network_identifier
        channel_identifier = channel_unlock_event.channel_identifier
        canonical_identifier = CanonicalIdentifier(
            chain_identifier=raiden.chain.network_id,
            token_network_address=token_network_identifier,
            channel_identifier=channel_identifier,
        )
        participant = channel_unlock_event.participant
        token_address = channel_unlock_event.token_address

        payment_channel: PaymentChannel = raiden.chain.payment_channel(
            canonical_identifier=canonical_identifier, )

        channel_state = get_channelstate_by_token_network_and_partner(
            chain_state=state_from_raiden(raiden),
            token_network_id=token_network_identifier,
            partner_address=participant,
        )

        if not channel_state:
            # channel was cleaned up already due to an unlock
            raise RaidenUnrecoverableError(
                f'Failed to find channel state with partner '
                f'{participant}, token_network:pex(token_network_identifier)',
            )

        our_address = channel_state.our_state.address
        our_locksroot = channel_state.our_state.onchain_locksroot

        partner_address = channel_state.partner_state.address
        partner_locksroot = channel_state.partner_state.onchain_locksroot

        # we want to unlock because there are on-chain unlocked locks
        search_events = our_locksroot != EMPTY_HASH
        # we want to unlock, because there are unlocked/unclaimed locks
        search_state_changes = partner_locksroot != EMPTY_HASH

        if not search_events and not search_state_changes:
            # In the case that someone else sent the unlock we do nothing
            # Check https://github.com/raiden-network/raiden/issues/3152
            # for more details
            log.warning(
                'Onchain unlock already mined',
                token_address=token_address,
                channel_identifier=canonical_identifier.channel_identifier,
                participant=participant,
            )
            return

        if search_state_changes:
            state_change_record = get_state_change_with_balance_proof_by_locksroot(
                storage=raiden.wal.storage,
                canonical_identifier=canonical_identifier,
                locksroot=partner_locksroot,
                sender=partner_address,
            )
            state_change_identifier = state_change_record.state_change_identifier

            if not state_change_identifier:
                raise RaidenUnrecoverableError(
                    f'Failed to find state that matches the current channel locksroots. '
                    f'chain_id:{raiden.chain.network_id} '
                    f'token:{to_checksum_address(token_address)} '
                    f'token_network:{to_checksum_address(token_network_identifier)} '
                    f'channel:{channel_identifier} '
                    f'participant:{to_checksum_address(participant)} '
                    f'our_locksroot:{to_hex(our_locksroot)} '
                    f'partner_locksroot:{to_hex(partner_locksroot)} ', )

            restored_channel_state = channel_state_until_state_change(
                raiden=raiden,
                payment_network_identifier=raiden.default_registry.address,
                token_address=token_address,
                channel_identifier=channel_identifier,
                state_change_identifier=state_change_identifier,
            )

            gain = get_batch_unlock_gain(restored_channel_state, )

            skip_unlock = (restored_channel_state.partner_state.address
                           == participant and gain.from_partner_locks == 0)
            if not skip_unlock:
                unlock(
                    raiden=raiden,
                    payment_channel=payment_channel,
                    end_state=restored_channel_state.partner_state,
                    participant=our_address,
                    partner=partner_address,
                )

        if search_events:
            event_record = get_event_with_balance_proof_by_locksroot(
                storage=raiden.wal.storage,
                canonical_identifier=canonical_identifier,
                locksroot=our_locksroot,
                recipient=partner_address,
            )
            state_change_identifier = event_record.state_change_identifier

            if not state_change_identifier:
                raise RaidenUnrecoverableError(
                    f'Failed to find event that match current channel locksroots. '
                    f'chain_id:{raiden.chain.network_id} '
                    f'token:{to_checksum_address(token_address)} '
                    f'token_network:{to_checksum_address(token_network_identifier)} '
                    f'channel:{channel_identifier} '
                    f'participant:{to_checksum_address(participant)} '
                    f'our_locksroot:{to_hex(our_locksroot)} '
                    f'partner_locksroot:{to_hex(partner_locksroot)} ', )

            restored_channel_state = channel_state_until_state_change(
                raiden=raiden,
                payment_network_identifier=raiden.default_registry.address,
                token_address=token_address,
                channel_identifier=canonical_identifier.channel_identifier,
                state_change_identifier=state_change_identifier,
            )

            gain = get_batch_unlock_gain(restored_channel_state, )

            skip_unlock = (restored_channel_state.our_state.address
                           == participant and gain.from_our_locks == 0)
            if not skip_unlock:
                unlock(
                    raiden=raiden,
                    payment_channel=payment_channel,
                    end_state=restored_channel_state.our_state,
                    participant=partner_address,
                    partner=our_address,
                )
Example #38
0
    def start_async(self) -> RaidenGreenletEvent:
        """ Start the node asynchronously. """
        self.start_event.clear()
        self.stop_event.clear()

        if self.database_dir is not None:
            self.db_lock.acquire(timeout=0)
            assert self.db_lock.is_locked

        # start the registration early to speed up the start
        if self.config['transport_type'] == 'udp':
            endpoint_registration_greenlet = gevent.spawn(
                self.discovery.register,
                self.address,
                self.config['transport']['udp']['external_ip'],
                self.config['transport']['udp']['external_port'],
            )

        # The database may be :memory:
        storage = sqlite.SQLiteStorage(self.database_path, serialize.PickleSerializer())
        self.wal = wal.restore_from_latest_snapshot(
            node.state_transition,
            storage,
        )

        if self.wal.state_manager.current_state is None:
            log.debug('No recoverable state available, created inital state')
            block_number = self.chain.block_number()

            state_change = ActionInitChain(
                random.Random(),
                block_number,
                self.chain.node_address,
                self.chain.network_id,
            )
            self.wal.log_and_dispatch(state_change, block_number)
            payment_network = PaymentNetworkState(
                self.default_registry.address,
                [],  # empty list of token network states as it's the node's startup
            )
            state_change = ContractReceiveNewPaymentNetwork(
                constants.NULL_ADDRESS,
                payment_network,
            )
            self.handle_state_change(state_change)

            # On first run Raiden needs to fetch all events for the payment
            # network, to reconstruct all token network graphs and find opened
            # channels
            last_log_block_number = 0
        else:
            # The `Block` state change is dispatched only after all the events
            # for that given block have been processed, filters can be safely
            # installed starting from this position without losing events.
            last_log_block_number = views.block_number(self.wal.state_manager.current_state)
            log.debug('Restored state from WAL', last_restored_block=last_log_block_number)

        # Restore the current snapshot group
        self.snapshot_group = last_log_block_number // SNAPSHOT_BLOCK_COUNT

        # Install the filters using the correct from_block value, otherwise
        # blockchain logs can be lost.
        self.install_all_blockchain_filters(
            self.default_registry,
            self.default_secret_registry,
            last_log_block_number,
        )

        # Complete the first_run of the alarm task and synchronize with the
        # blockchain since the last run.
        #
        # Notes about setup order:
        # - The filters must be polled after the node state has been primed,
        # otherwise the state changes won't have effect.
        # - The alarm must complete its first run  before the transport is started,
        #  to avoid rejecting messages for unknown channels.
        self.alarm.register_callback(self._callback_new_block)

        self.alarm.first_run()

        chain_state = views.state_from_raiden(self)
        # Dispatch pending transactions
        pending_transactions = views.get_pending_transactions(
            chain_state,
        )
        log.debug(
            'Processing pending transactions',
            num_pending_transactions=len(pending_transactions),
        )
        with self.dispatch_events_lock:
            for transaction in pending_transactions:
                on_raiden_event(self, transaction)

        self.alarm.start()

        queueids_to_queues = views.get_all_messagequeues(chain_state)
        self.transport.start(self, queueids_to_queues)

        # Health check needs the transport layer
        self.start_neighbours_healthcheck()

        if self.config['transport_type'] == 'udp':
            def set_start_on_registration(_):
                self.start_event.set()

            endpoint_registration_greenlet.link_safe(set_start_on_registration)
        else:
            self.start_event.set()

        return self.start_event
Example #39
0
    def open(
        self,
        registry_address: typing.PaymentNetworkID,
        partner_address: typing.Address,
        token_address: typing.TokenAddress,
        settle_timeout: typing.BlockTimeout = None,
        total_deposit: typing.TokenAmount = None,
    ):
        log.debug(
            'Opening channel',
            node=pex(self.raiden_api.address),
            registry_address=to_checksum_address(registry_address),
            partner_address=to_checksum_address(partner_address),
            token_address=to_checksum_address(token_address),
            settle_timeout=settle_timeout,
        )
        try:
            token = self.raiden_api.raiden.chain.token(token_address)
        except AddressWithoutCode as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        balance = token.balance_of(self.raiden_api.raiden.address)

        if total_deposit is not None and total_deposit > balance:
            error_msg = 'Not enough balance to deposit. {} Available={} Needed={}'.format(
                pex(token_address),
                balance,
                total_deposit,
            )
            return api_error(
                errors=error_msg,
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        try:
            self.raiden_api.channel_open(
                registry_address,
                token_address,
                partner_address,
                settle_timeout,
            )
        except (InvalidAddress, InvalidSettleTimeout, SamePeerAddress,
                AddressWithoutCode, DuplicatedChannelError,
                TokenNotRegistered) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        except (InsufficientFunds, InsufficientGasReserve) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        if total_deposit:
            # make initial deposit
            log.debug(
                'Depositing to new channel',
                node=pex(self.raiden_api.address),
                registry_address=to_checksum_address(registry_address),
                token_address=to_checksum_address(token_address),
                partner_address=to_checksum_address(partner_address),
                total_deposit=total_deposit,
            )
            try:
                self.raiden_api.set_total_channel_deposit(
                    registry_address=registry_address,
                    token_address=token_address,
                    partner_address=partner_address,
                    total_deposit=total_deposit,
                )
            except InsufficientFunds as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.PAYMENT_REQUIRED,
                )
            except (DepositOverLimit, DepositMismatch) as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.CONFLICT,
                )

        channel_state = views.get_channelstate_for(
            views.state_from_raiden(self.raiden_api.raiden),
            registry_address,
            token_address,
            partner_address,
        )

        result = self.channel_schema.dump(channel_state)

        return api_response(
            result=result.data,
            status_code=HTTPStatus.CREATED,
        )
Example #40
0
    def open(
        self,
        registry_address: typing.PaymentNetworkID,
        partner_address: typing.Address,
        token_address: typing.TokenAddress,
        settle_timeout: typing.BlockTimeout = None,
        reveal_timeout: typing.BlockTimeout = None,
        total_deposit: typing.TokenAmount = None,
    ):
        log.debug(
            'Opening channel',
            registry_address=to_checksum_address(registry_address),
            partner_address=to_checksum_address(partner_address),
            token_address=to_checksum_address(token_address),
            settle_timeout=settle_timeout,
            reveal_timeout=reveal_timeout,
        )
        try:
            self.raiden_api.channel_open(
                registry_address,
                token_address,
                partner_address,
                settle_timeout,
                reveal_timeout,
            )
        except EthNodeCommunicationError:
            return api_response(
                result='',
                status_code=HTTPStatus.ACCEPTED,
            )
        except (InvalidAddress, InvalidSettleTimeout, SamePeerAddress,
                AddressWithoutCode, DuplicatedChannelError,
                TokenNotRegistered) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        except (InsufficientFunds, InsufficientGasReserve) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        if total_deposit:
            # make initial deposit
            log.debug(
                'Depositing to new channel',
                registry_address=to_checksum_address(registry_address),
                token_address=to_checksum_address(token_address),
                partner_address=to_checksum_address(partner_address),
                total_deposit=total_deposit,
            )
            try:
                self.raiden_api.set_total_channel_deposit(
                    registry_address=registry_address,
                    token_address=token_address,
                    partner_address=partner_address,
                    total_deposit=total_deposit,
                )
            except EthNodeCommunicationError:
                return api_response(
                    result='',
                    status_code=HTTPStatus.ACCEPTED,
                )
            except InsufficientFunds as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.PAYMENT_REQUIRED,
                )
            except (DepositOverLimit, DepositMismatch) as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.CONFLICT,
                )

        channel_state = views.get_channelstate_for(
            views.state_from_raiden(self.raiden_api.raiden),
            registry_address,
            token_address,
            partner_address,
        )

        result = self.channel_schema.dump(channel_state)

        return api_response(
            result=result.data,
            status_code=HTTPStatus.CREATED,
        )
Example #41
0
    def transfer_async(
        self,
        registry_address: TokenNetworkRegistryAddress,
        token_address: TokenAddress,
        amount: PaymentAmount,
        target: TargetAddress,
        identifier: PaymentID = None,
        secret: Secret = None,
        secrethash: SecretHash = None,
        lock_timeout: BlockTimeout = None,
    ) -> "PaymentStatus":
        current_state = views.state_from_raiden(self.raiden)
        token_network_registry_address = self.raiden.default_registry.address

        if not isinstance(amount, int):  # pragma: no unittest
            raise InvalidAmount("Amount not a number")

        if Address(target) == self.address:
            raise SamePeerAddress("Address must be different than ours")

        if amount <= 0:
            raise InvalidAmount("Amount negative")

        if amount > UINT256_MAX:
            raise InvalidAmount("Amount too large")

        if not is_binary_address(token_address):
            raise InvalidBinaryAddress("token address is not valid.")

        if token_address not in views.get_token_identifiers(
                current_state, registry_address):
            raise UnknownTokenAddress("Token address is not known.")

        if not is_binary_address(target):
            raise InvalidBinaryAddress("target address is not valid.")

        valid_tokens = views.get_token_identifiers(
            views.state_from_raiden(self.raiden), registry_address)
        if token_address not in valid_tokens:
            raise UnknownTokenAddress("Token address is not known.")

        if secret is not None and not isinstance(secret, T_Secret):
            raise InvalidSecret("secret is not valid.")

        if secrethash is not None and not isinstance(secrethash, T_SecretHash):
            raise InvalidSecretHash("secrethash is not valid.")

        if identifier is None:
            identifier = create_default_identifier()

        if identifier <= 0:
            raise InvalidPaymentIdentifier(
                "Payment identifier cannot be 0 or negative")

        if identifier > UINT64_MAX:
            raise InvalidPaymentIdentifier("Payment identifier is too large")

        log.debug(
            "Initiating transfer",
            initiator=to_checksum_address(self.raiden.address),
            target=to_checksum_address(target),
            token=to_checksum_address(token_address),
            amount=amount,
            identifier=identifier,
        )

        token_network_address = views.get_token_network_address_by_token_address(
            chain_state=current_state,
            token_network_registry_address=token_network_registry_address,
            token_address=token_address,
        )

        if token_network_address is None:
            raise UnknownTokenAddress(
                f"Token {to_checksum_address(token_address)} is not registered "
                f"with the network {to_checksum_address(registry_address)}.")

        payment_status = self.raiden.mediated_transfer_async(
            token_network_address=token_network_address,
            amount=amount,
            target=target,
            identifier=identifier,
            secret=secret,
            secrethash=secrethash,
            lock_timeout=lock_timeout,
        )
        return payment_status
Example #42
0
    def get_channel_list(
        self,
        registry_address: TokenNetworkRegistryAddress,
        token_address: TokenAddress = None,
        partner_address: Address = None,
    ) -> List[NettingChannelState]:
        """Returns a list of channels associated with the optionally given
           `token_address` and/or `partner_address`.

        Args:
            token_address: an optionally provided token address
            partner_address: an optionally provided partner address

        Return:
            A list containing all channels the node participates. Optionally
            filtered by a token address and/or partner address.

        Raises:
            KeyError: An error occurred when the token address is unknown to the node.
        """
        if registry_address and not is_binary_address(registry_address):
            raise InvalidBinaryAddress(
                "Expected binary address format for registry in get_channel_list"
            )

        if token_address and not is_binary_address(token_address):
            raise InvalidBinaryAddress(
                "Expected binary address format for token in get_channel_list")

        if partner_address:
            if not is_binary_address(partner_address):
                raise InvalidBinaryAddress(
                    "Expected binary address format for partner in get_channel_list"
                )
            if not token_address:
                raise UnknownTokenAddress(
                    "Provided a partner address but no token address")

        if token_address and partner_address:
            channel_state = views.get_channelstate_for(
                chain_state=views.state_from_raiden(self.raiden),
                token_network_registry_address=registry_address,
                token_address=token_address,
                partner_address=partner_address,
            )

            if channel_state:
                result = [channel_state]
            else:
                result = []

        elif token_address:
            result = views.list_channelstate_for_tokennetwork(
                chain_state=views.state_from_raiden(self.raiden),
                token_network_registry_address=registry_address,
                token_address=token_address,
            )

        else:
            result = views.list_all_channelstate(
                chain_state=views.state_from_raiden(self.raiden))

        return result
Example #43
0
    def open(
        self,
        registry_address,
        partner_address,
        token_address,
        settle_timeout=None,
        reveal_timeout=None,
        balance=None,
    ):

        try:
            self.raiden_api.channel_open(
                registry_address,
                token_address,
                partner_address,
                settle_timeout,
                reveal_timeout,
            )
        except EthNodeCommunicationError:
            return api_response(
                result='',
                status_code=HTTPStatus.ACCEPTED,
            )
        except (InvalidAddress, InvalidSettleTimeout, SamePeerAddress,
                AddressWithoutCode, DuplicatedChannelError,
                TokenNotRegistered) as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.CONFLICT,
            )
        except InsufficientFunds as e:
            return api_error(
                errors=str(e),
                status_code=HTTPStatus.PAYMENT_REQUIRED,
            )

        if balance:
            # make initial deposit
            try:
                self.raiden_api.set_total_channel_deposit(
                    registry_address,
                    token_address,
                    partner_address,
                    balance,
                )
            except EthNodeCommunicationError:
                return api_response(
                    result='',
                    status_code=HTTPStatus.ACCEPTED,
                )
            except InsufficientFunds as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.PAYMENT_REQUIRED,
                )
            except DepositOverLimit as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.CONFLICT,
                )
            except DepositMismatch as e:
                return api_error(
                    errors=str(e),
                    status_code=HTTPStatus.CONFLICT,
                )

        channel_state = views.get_channelstate_for(
            views.state_from_raiden(self.raiden_api.raiden),
            registry_address,
            token_address,
            partner_address,
        )

        result = self.channel_schema.dump(channel_state)

        return api_response(
            result=result.data,
            status_code=HTTPStatus.CREATED,
        )
Example #44
0
def test_settle_is_automatically_called(raiden_network, token_addresses):
    """Settle is automatically called by one of the nodes."""
    app0, app1 = raiden_network
    registry_address = app0.raiden.default_registry.address
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(app0), app0.raiden.default_registry.address,
        token_address)
    assert token_network_address
    token_network = views.get_token_network_by_address(
        views.state_from_app(app0), token_network_address)
    assert token_network

    channel_identifier = get_channelstate(app0, app1,
                                          token_network_address).identifier

    assert (channel_identifier
            in token_network.partneraddresses_to_channelidentifiers[
                app1.raiden.address])

    # A ChannelClose event will be generated, this will be polled by both apps
    # and each must start a task for calling settle
    RaidenAPI(app1.raiden).channel_close(registry_address, token_address,
                                         app0.raiden.address)

    waiting.wait_for_close(
        app0.raiden,
        registry_address,
        token_address,
        [channel_identifier],
        app0.raiden.alarm.sleep_time,
    )

    channel_state = views.get_channelstate_for(
        views.state_from_raiden(app0.raiden), registry_address, token_address,
        app1.raiden.address)
    assert channel_state
    assert channel_state.close_transaction
    assert channel_state.close_transaction.finished_block_number

    waiting.wait_for_settle(
        app0.raiden,
        registry_address,
        token_address,
        [channel_identifier],
        app0.raiden.alarm.sleep_time,
    )

    token_network = views.get_token_network_by_address(
        views.state_from_app(app0), token_network_address)
    assert token_network

    assert (channel_identifier
            not in token_network.partneraddresses_to_channelidentifiers[
                app1.raiden.address])

    state_changes = app0.raiden.wal.storage.get_statechanges_by_range(
        RANGE_ALL_STATE_CHANGES)

    assert search_for_item(
        state_changes,
        ContractReceiveChannelClosed,
        {
            "token_network_address": token_network_address,
            "channel_identifier": channel_identifier,
            "transaction_from": app1.raiden.address,
            "block_number":
            channel_state.close_transaction.finished_block_number,
        },
    )

    assert search_for_item(
        state_changes,
        ContractReceiveChannelSettled,
        {
            "token_network_address": token_network_address,
            "channel_identifier": channel_identifier
        },
    )
Example #45
0
def test_mediated_transfer_with_node_consuming_more_than_allocated_fee(
        raiden_network, number_of_nodes, deposit, token_addresses,
        network_wait):
    """
    Tests a mediator node consuming more fees than allocated.
    Which means that the initiator will not reveal the secret
    to the target.
    """
    app0, app1, app2 = raiden_network
    token_address = token_addresses[0]
    chain_state = views.state_from_app(app0)
    token_network_registry_address = app0.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state, token_network_registry_address, token_address)
    assert token_network_address
    amount = PaymentAmount(100)
    fee = FeeAmount(5)
    fee_margin = calculate_fee_margin(amount, fee)

    app1_app2_channel_state = views.get_channelstate_by_token_network_and_partner(
        chain_state=views.state_from_raiden(app1.raiden),
        token_network_address=token_network_address,
        partner_address=app2.raiden.address,
    )
    assert app1_app2_channel_state

    # Let app1 consume all of the allocated mediation fee
    app1_app2_channel_state.fee_schedule = FeeScheduleState(
        flat=FeeAmount(fee * 2))

    secret = factories.make_secret(0)
    secrethash = sha256_secrethash(secret)

    wait_message_handler = WaitForMessage()
    app0.raiden.message_handler = wait_message_handler
    secret_request_received = wait_message_handler.wait_for_message(
        SecretRequest, {"secrethash": secrethash})

    def get_best_routes_with_fees(*args, **kwargs):
        error_msg, routes, uuid = get_best_routes(*args, **kwargs)
        for r in routes:
            r.estimated_fee = fee
        return error_msg, routes, uuid

    with patch("raiden.routing.get_best_routes", get_best_routes_with_fees):
        app0.raiden.start_mediated_transfer_with_secret(
            token_network_address=token_network_address,
            amount=amount,
            target=app2.raiden.address,
            identifier=1,
            secret=secret,
        )

    app0_app1_channel_state = views.get_channelstate_by_token_network_and_partner(
        chain_state=views.state_from_raiden(app0.raiden),
        token_network_address=token_network_address,
        partner_address=app1.raiden.address,
    )
    assert app0_app1_channel_state

    msg = "App0 should have the transfer in secrethashes_to_lockedlocks"
    assert secrethash in app0_app1_channel_state.our_state.secrethashes_to_lockedlocks, msg

    msg = "App0 should have locked the amount + fee"
    lock_amount = app0_app1_channel_state.our_state.secrethashes_to_lockedlocks[
        secrethash].amount
    assert lock_amount == amount + fee + fee_margin, msg

    secret_request_received.wait()

    app0_chain_state = views.state_from_app(app0)
    initiator_task = cast(
        InitiatorTask,
        app0_chain_state.payment_mapping.secrethashes_to_task[secrethash])

    msg = "App0 should have never revealed the secret"
    transfer_state = initiator_task.manager_state.initiator_transfers[
        secrethash].transfer_state
    assert transfer_state != "transfer_secret_revealed", msg
Example #46
0
def reveal_secret_with_resolver(
        raiden: "RaidenService", chain_state: ChainState,
        secret_request_event: SendSecretRequest) -> bool:

    resolver_endpoint = raiden.config.resolver_endpoint
    if not resolver_endpoint:
        return False

    log.debug("Using resolver to fetch secret",
              resolver_endpoint=resolver_endpoint)

    assert isinstance(raiden.wal,
                      WriteAheadLog), "RaidenService has not been started"
    current_state = raiden.wal.state_manager.current_state

    if current_state is None:
        return False

    task = current_state.payment_mapping.secrethashes_to_task[
        secret_request_event.secrethash]
    token = task.target_state.transfer.token

    request = {
        "token": to_hex(token),
        "secrethash": to_hex(secret_request_event.secrethash),
        "amount": secret_request_event.amount,
        "payment_identifier": secret_request_event.payment_identifier,
        "payment_sender": to_hex(secret_request_event.recipient),
        "expiration": secret_request_event.expiration,
        "payment_recipient": to_hex(raiden.address),
        "chain_id": chain_state.chain_id,
    }

    # loop until we get a valid response from the resolver or until timeout
    while True:
        current_state = views.state_from_raiden(raiden)

        if secret_request_event.expiration < current_state.block_number:
            log.debug("Stopped using resolver, transfer expired",
                      resolver_endpoint=resolver_endpoint)
            # The locked transfer is expired now, so it makes no sense to continue processing it.
            # When returning `False`, the event handler would contiue processing the events, which
            # is not what is wanted here, so we return `True` to cancel
            return True

        response = None

        try:
            # before calling resolver, update block height
            request["chain_height"] = chain_state.block_number
            response = requests.post(resolver_endpoint, json=request)
        except requests.exceptions.RequestException:
            pass

        # no response means the resolver could not be reached and we should try again
        if response is not None:
            if response.status_code == HTTPStatus.OK:
                # request succeeded so we can break the loop and use the secret
                break
            elif response.status_code == HTTPStatus.SERVICE_UNAVAILABLE:
                # treat SERVICE UNAVAILABLE as if the resolver could not be reached and try again
                pass
            else:
                # on any other status code, treat the request as having failed and return False
                return False
        gevent.sleep(5)

    log.debug("Got secret from resolver, dispatching secret reveal",
              resolver_endpoint=resolver_endpoint)
    state_change = ReceiveSecretReveal(
        sender=secret_request_event.recipient,
        secret=Secret(to_bytes(hexstr=json.loads(response.content)["secret"])),
    )
    raiden.handle_and_track_state_changes([state_change])
    return True
Example #47
0
def test_send_queued_messages_after_restart(  # pylint: disable=unused-argument
    raiden_network: List[App],
    restart_node: RestartNode,
    deposit: TokenAmount,
    token_addresses: List[TokenAddress],
    network_wait: float,
):
    """Test re-sending of undelivered messages on node restart"""
    app0, app1 = raiden_network
    token_address = token_addresses[0]
    chain_state = views.state_from_app(app0)
    token_network_registry_address = app0.raiden.default_registry.address
    token_network_address = views.get_token_network_address_by_token_address(
        chain_state, token_network_registry_address, token_address)
    assert token_network_address

    number_of_transfers = 7
    amount_per_transfer = PaymentAmount(1)
    total_transferred_amount = TokenAmount(amount_per_transfer *
                                           number_of_transfers)

    # Make sure none of the transfers will be sent before the restart
    transfers = []
    for secret_seed in range(number_of_transfers):
        secret = make_secret(secret_seed)
        secrethash = sha256_secrethash(secret)
        transfers.append((create_default_identifier(), amount_per_transfer,
                          secret, secrethash))

        assert isinstance(app0.raiden.raiden_event_handler,
                          HoldRaidenEventHandler)  # for mypy
        app0.raiden.raiden_event_handler.hold(
            SendLockedTransfer,
            {"transfer": {
                "lock": {
                    "secrethash": secrethash
                }
            }})

    for identifier, amount, secret, _ in transfers:
        app0.raiden.mediated_transfer_async(
            token_network_address=token_network_address,
            amount=amount,
            target=TargetAddress(app1.raiden.address),
            identifier=identifier,
            secret=secret,
        )

    app0.stop()

    # Restart the app. The pending transfers must be processed.
    new_transport = MatrixTransport(
        config=app0.raiden.config.transport,
        environment=app0.raiden.config.environment_type)
    raiden_event_handler = RaidenEventHandler()
    message_handler = MessageHandler()
    app0_restart = App(
        config=app0.config,
        rpc_client=app0.raiden.rpc_client,
        proxy_manager=app0.raiden.proxy_manager,
        query_start_block=BlockNumber(0),
        default_registry=app0.raiden.default_registry,
        default_secret_registry=app0.raiden.default_secret_registry,
        default_service_registry=app0.raiden.default_service_registry,
        default_user_deposit=app0.raiden.default_user_deposit,
        default_one_to_n_address=app0.raiden.default_one_to_n_address,
        default_msc_address=app0.raiden.default_msc_address,
        transport=new_transport,
        raiden_event_handler=raiden_event_handler,
        message_handler=message_handler,
        routing_mode=RoutingMode.PRIVATE,
    )

    del app0
    restart_node(app0_restart)

    # XXX: There is no synchronization among the app and the test, so it is
    # possible between `start` and the check below that some of the transfers
    # have completed, making it flaky.
    #
    # Make sure the transfers are in the queue and fail otherwise.
    chain_state = views.state_from_raiden(app0_restart.raiden)
    for _, _, _, secrethash in transfers:
        msg = "The secrethashes of the pending transfers must be in the queue after a restart."
        assert secrethash in chain_state.payment_mapping.secrethashes_to_task, msg

    timeout = block_offset_timeout(
        app1.raiden, "Timeout waiting for balance update of app0")
    with watch_for_unlock_failures(*raiden_network), timeout:
        waiting.wait_for_payment_balance(
            raiden=app0_restart.raiden,
            token_network_registry_address=token_network_registry_address,
            token_address=token_address,
            partner_address=app1.raiden.address,
            target_address=app1.raiden.address,
            target_balance=total_transferred_amount,
            retry_timeout=network_wait,
        )
        timeout.exception_to_throw = ValueError(
            "Timeout waiting for balance update of app1")
        waiting.wait_for_payment_balance(
            raiden=app1.raiden,
            token_network_registry_address=token_network_registry_address,
            token_address=token_address,
            partner_address=app0_restart.raiden.address,
            target_address=app1.raiden.address,
            target_balance=total_transferred_amount,
            retry_timeout=network_wait,
        )

    assert_synced_channel_state(
        token_network_address,
        app0_restart,
        Balance(deposit - total_transferred_amount),
        [],
        app1,
        Balance(deposit + total_transferred_amount),
        [],
    )
    new_transport.stop()
Example #48
0
 def get_tokens_list(self, registry_address: TokenNetworkRegistryAddress) -> List[TokenAddress]:
     """Returns a list of tokens the node knows about"""
     return views.get_token_identifiers(
         chain_state=views.state_from_raiden(self.raiden),
         token_network_registry_address=registry_address,
     )
Example #49
0
 def get_node_network_state(self, node_address: Address) -> NetworkState:
     """ Returns the currently network status of `node_address`. """
     return views.get_node_network_status(
         chain_state=views.state_from_raiden(self.raiden),
         node_address=node_address)
Example #50
0
    def set_total_channel_withdraw(
        self,
        registry_address: TokenNetworkRegistryAddress,
        token_address: TokenAddress,
        partner_address: Address,
        total_withdraw: WithdrawAmount,
        retry_timeout: NetworkTimeout = DEFAULT_RETRY_TIMEOUT,
    ) -> None:
        """ Set the `total_withdraw` in the channel with the peer at `partner_address` and the
        given `token_address`.

        Raises:
            InvalidBinaryAddress: If either token_address or partner_address is not
                20 bytes long.
            RaidenUnrecoverableError: May happen for multiple reasons:
                - During preconditions checks, if the channel was not open
                  at the time of the approve_and_set_total_deposit call.
                - If the transaction fails during gas estimation or
                  if a previous withdraw transaction with the same value
                   was already mined.
            DepositMismatch: The total withdraw amount did not increase.
        """
        chain_state = views.state_from_raiden(self.raiden)

        token_addresses = views.get_token_identifiers(chain_state,
                                                      registry_address)
        channel_state = views.get_channelstate_for(
            chain_state=chain_state,
            token_network_registry_address=registry_address,
            token_address=token_address,
            partner_address=partner_address,
        )

        if not is_binary_address(token_address):
            raise InvalidBinaryAddress(
                "Expected binary address format for token in channel deposit")

        if not is_binary_address(partner_address):
            raise InvalidBinaryAddress(
                "Expected binary address format for partner in channel deposit"
            )

        if token_address not in token_addresses:
            raise UnknownTokenAddress("Unknown token address")

        if channel_state is None:
            raise NonexistingChannel(
                "No channel with partner_address for the given token")

        if total_withdraw <= channel_state.our_total_withdraw:
            raise WithdrawMismatch(
                f"Total withdraw {total_withdraw} did not increase")

        current_balance = channel.get_balance(
            sender=channel_state.our_state,
            receiver=channel_state.partner_state)
        amount_to_withdraw = total_withdraw - channel_state.our_total_withdraw
        if amount_to_withdraw > current_balance:
            raise InsufficientFunds(
                "The withdraw of {} is bigger than the current balance of {}".
                format(amount_to_withdraw, current_balance))

        self.raiden.withdraw(
            canonical_identifier=channel_state.canonical_identifier,
            total_withdraw=total_withdraw)

        waiting.wait_for_withdraw_complete(
            raiden=self.raiden,
            canonical_identifier=channel_state.canonical_identifier,
            total_withdraw=total_withdraw,
            retry_timeout=retry_timeout,
        )
Example #51
0
def test_participant_selection(raiden_network, token_addresses, skip_if_tester):
    registry_address = raiden_network[0].raiden.default_registry.address

    # pylint: disable=too-many-locals
    token_address = token_addresses[0]

    # connect the first node (will register the token if necessary)
    RaidenAPI(raiden_network[0].raiden).token_network_connect(
        registry_address,
        token_address,
        100,
    )

    # connect the other nodes
    connect_greenlets = [
        gevent.spawn(
            RaidenAPI(app.raiden).token_network_connect,
            registry_address,
            token_address,
            100,
        )

        for app in raiden_network[1:]
    ]
    gevent.wait(connect_greenlets)

    token_network_registry_address = views.get_token_network_identifier_by_token_address(
        views.state_from_raiden(raiden_network[0].raiden),
        payment_network_id=registry_address,
        token_address=token_address,
    )
    connection_managers = [
        app.raiden.connection_manager_for_token_network(
            token_network_registry_address,
        ) for app in raiden_network
    ]

    assert wait_for_saturated(
        connection_managers,
        registry_address,
        token_address,
    ) is True

    assert saturated_count(
        connection_managers,
        registry_address,
        token_address,
    ) == len(connection_managers)

    # ensure unpartitioned network
    for app in raiden_network:
        node_state = views.state_from_raiden(app.raiden)
        network_state = views.get_token_network_by_token_address(
            node_state,
            registry_address,
            token_address,
        )
        assert network_state is not None
        for target in raiden_network:
            if target.raiden.address == app.raiden.address:
                continue
            routes = routing.get_best_routes(
                node_state,
                network_state.address,
                app.raiden.address,
                target.raiden.address,
                1,
                None,
            )
            assert routes is not None

    # create a transfer to the leaving node, so we have a channel to settle
    sender = raiden_network[-1].raiden
    receiver = raiden_network[0].raiden

    registry_address = sender.default_registry.address
    # assert there is a direct channel receiver -> sender (vv)
    receiver_channel = RaidenAPI(receiver).get_channel_list(
        registry_address=registry_address,
        token_address=token_address,
        partner_address=sender.address,
    )
    assert len(receiver_channel) == 1
    receiver_channel = receiver_channel[0]

    # assert there is a direct channel sender -> receiver
    sender_channel = RaidenAPI(sender).get_channel_list(
        registry_address=registry_address,
        token_address=token_address,
        partner_address=receiver.address,
    )
    assert len(sender_channel) == 1
    sender_channel = sender_channel[0]

    exception = ValueError('partner not reachable')
    with gevent.Timeout(30, exception=exception):
        waiting.wait_for_healthy(sender, receiver.address, 1)

    amount = 1
    RaidenAPI(sender).transfer_and_wait(
        registry_address,
        token_address,
        amount,
        receiver.address,
        transfer_timeout=10,
    )

    exception = ValueError('timeout while waiting for incoming transaction')
    with gevent.Timeout(30, exception=exception):
        wait_for_transaction(
            receiver,
            registry_address,
            token_address,
            sender.address,
        )

    # test `leave()` method
    connection_manager = connection_managers[0]

    timeout = (
        sender_channel.settle_timeout *
        connection_manager.raiden.chain.estimate_blocktime() *
        10
    )

    assert timeout > 0
    exception = ValueError('timeout while waiting for leave')
    with gevent.Timeout(timeout, exception=exception):
        RaidenAPI(raiden_network[0].raiden).token_network_leave(
            registry_address,
            token_address,
        )

    before_block = connection_manager.raiden.chain.block_number()
    wait_blocks = sender_channel.settle_timeout + 10
    # wait until both chains are synced?
    wait_until_block(
        connection_manager.raiden.chain,
        before_block + wait_blocks,
    )
    wait_until_block(
        receiver.chain,
        before_block + wait_blocks,
    )
    receiver_channel = RaidenAPI(receiver).get_channel_list(
        registry_address=registry_address,
        token_address=token_address,
        partner_address=sender.address,
    )
    assert receiver_channel[0].settle_transaction is not None
Example #52
0
    def connect(
        self,
        funds: typing.TokenAmount,
        initial_channel_target: int = 3,
        joinable_funds_target: float = 0.4,
    ):
        """Connect to the network.

        Subsequent calls to `connect` are allowed, but will only affect the spendable
        funds and the connection strategy parameters for the future. `connect` will not
        close any channels.

        Note: the ConnectionManager does not discriminate manually opened channels from
        automatically opened ones. If the user manually opened channels, those deposit
        amounts will affect the funding per channel and the number of new channels opened.

        Args:
            funds: Target amount of tokens spendable to join the network.
            initial_channel_target: Target number of channels to open.
            joinable_funds_target: Amount of funds not initially assigned.
        """
        token = self.raiden.chain.token(self.token_address)
        token_balance = token.balance_of(self.raiden.address)

        if token_balance < funds:
            raise InvalidAmount(
                f'Insufficient balance for token {pex(self.token_address)}', )

        if funds <= 0:
            raise InvalidAmount(
                'The funds to use in the connection need to be a positive integer',
            )

        if joinable_funds_target < 0 or joinable_funds_target > 1:
            raise InvalidAmount(
                f'joinable_funds_target should be between 0 and 1. Given: {joinable_funds_target}',
            )

        with self.lock:
            self.funds = funds
            self.initial_channel_target = initial_channel_target
            self.joinable_funds_target = joinable_funds_target

            log_open_channels(self.raiden, self.registry_address,
                              self.token_address, funds)

            qty_network_channels = views.count_token_network_channels(
                views.state_from_raiden(self.raiden),
                self.registry_address,
                self.token_address,
            )

            if not qty_network_channels:
                log.info(
                    'Bootstrapping token network.',
                    node=pex(self.raiden.address),
                    network_id=pex(self.registry_address),
                    token_id=pex(self.token_address),
                )
                self.api.channel_open(
                    self.registry_address,
                    self.token_address,
                    self.BOOTSTRAP_ADDR,
                )
            else:
                self._open_channels()
Example #53
0
    def join_channel(self, partner_address, partner_deposit):
        """Will be called, when we were selected as channel partner by another
        node. It will fund the channel with up to the partners deposit, but
        not more than remaining funds or the initial funding per channel.

        If the connection manager has no funds, this is a noop.
        """

        # Consider this race condition:
        #
        # - Partner opens the channel and starts the deposit.
        # - This nodes learns about the new channel, starts ConnectionManager's
        #   retry_connect, which will start a deposit for this half of the
        #   channel.
        # - This node learns about the partner's deposit before its own.
        #   join_channel is called which will try to deposit again.
        #
        # To fix this race, first the node must wait for the pending operations
        # to finish, because in them could be a deposit, and then deposit must
        # be called only if the channel is still not funded.
        token_network_proxy = self.raiden.chain.token_network(
            self.token_network_identifier)

        # Wait for any pending operation in the channel to complete, before
        # deciding on the deposit
        with self.lock, token_network_proxy.channel_operations_lock[
                partner_address]:
            channel_state = views.get_channelstate_for(
                views.state_from_raiden(self.raiden),
                self.token_network_identifier,
                self.token_address,
                partner_address,
            )

            if not channel_state:
                return

            joining_funds = min(
                partner_deposit,
                self._funds_remaining,
                self._initial_funding_per_partner,
            )
            if joining_funds <= 0 or self._leaving_state:
                return

            if joining_funds <= channel_state.our_state.contract_balance:
                return

            try:
                self.api.set_total_channel_deposit(
                    self.registry_address,
                    self.token_address,
                    partner_address,
                    joining_funds,
                )
            except RaidenRecoverableError:
                log.info(
                    'Channel not in opened state',
                    node=pex(self.raiden.address),
                )
            except InvalidDBData:
                raise
            except RaidenUnrecoverableError as e:
                should_crash = (
                    self.raiden.config['environment_type'] !=
                    Environment.PRODUCTION
                    or self.raiden.config['unrecoverable_error_should_crash'])
                if should_crash:
                    raise

                log.critical(
                    str(e),
                    node=pex(self.raiden.address),
                )
            else:
                log.info(
                    'Joined a channel',
                    node=pex(self.raiden.address),
                    partner=pex(partner_address),
                    funds=joining_funds,
                )
Example #54
0
    def _open_channels(self) -> bool:
        """ Open channels until there are `self.initial_channel_target`
        channels open. Do nothing if there are enough channels open already.

        Note:
            - This method must be called with the lock held.
        Return:
            - False if no channels could be opened
        """

        open_channels = views.get_channelstate_open(
            chain_state=views.state_from_raiden(self.raiden),
            payment_network_id=self.registry_address,
            token_address=self.token_address,
        )
        open_channels = [
            channel_state for channel_state in open_channels
            if channel_state.partner_state.address != self.BOOTSTRAP_ADDR
        ]
        funded_channels = [
            channel_state for channel_state in open_channels
            if channel_state.our_state.contract_balance >=
            self._initial_funding_per_partner
        ]
        nonfunded_channels = [
            channel_state for channel_state in open_channels
            if channel_state not in funded_channels
        ]
        possible_new_partners = self._find_new_partners()
        if possible_new_partners == 0:
            return False

        # if we already met our target, break
        if len(funded_channels) >= self.initial_channel_target:
            return False
        # if we didn't, but there's no nonfunded channels and no available partners
        # it means the network is smaller than our target, so we should also break
        if not nonfunded_channels and possible_new_partners == 0:
            return False

        n_to_join = self.initial_channel_target - len(funded_channels)
        nonfunded_partners = [
            channel_state.partner_state.address
            for channel_state in nonfunded_channels
        ]
        # first, fund nonfunded channels, then open and fund with possible_new_partners,
        # until initial_channel_target of funded channels is met
        join_partners = (nonfunded_partners +
                         possible_new_partners)[:n_to_join]

        log.debug(
            'Spawning greenlets to join partners',
            node=pex(self.raiden.address),
            num_greenlets=len(join_partners),
        )

        greenlets = [
            gevent.spawn(self._join_partner, partner)
            for partner in join_partners
        ]
        gevent.joinall(greenlets, raise_error=True)
        return True
Example #55
0
 def get_node_network_state(self, node_address: typing.Address):
     """ Returns the currently network status of `node_address`. """
     return views.get_node_network_status(
         views.state_from_raiden(self.raiden),
         node_address,
     )
Example #56
0
def run_smoketests(raiden_service: RaidenService,
                   test_config: Dict,
                   debug: bool = False):
    """ Test that the assembled raiden_service correctly reflects the configuration from the
    smoketest_genesis. """
    try:
        chain = raiden_service.chain
        assert (
            raiden_service.default_registry.address == to_canonical_address(
                test_config['contracts']['registry_address']))
        assert (raiden_service.default_secret_registry.address ==
                to_canonical_address(
                    test_config['contracts']['secret_registry_address']))

        token_network_added_events = raiden_service.default_registry.filter_token_added_events(
        )
        token_addresses = [
            event['args']['token_address']
            for event in token_network_added_events
        ]

        assert token_addresses == [test_config['contracts']['token_address']]

        if test_config.get('transport') == 'udp':
            assert len(chain.address_to_discovery.keys()) == 1, repr(
                chain.address_to_discovery)
            assert (list(
                chain.address_to_discovery.keys())[0] == to_canonical_address(
                    test_config['contracts']['discovery_address']))
            discovery = list(chain.address_to_discovery.values())[0]
            assert discovery.endpoint_by_address(
                raiden_service.address) != TEST_ENDPOINT

        token_networks = views.get_token_network_addresses_for(
            views.state_from_raiden(raiden_service),
            raiden_service.default_registry.address,
        )
        assert len(token_networks) == 1

        channel_state = views.get_channelstate_for(
            views.state_from_raiden(raiden_service),
            raiden_service.default_registry.address,
            token_networks[0],
            unhexlify(TEST_PARTNER_ADDRESS),
        )

        distributable = channel.get_distributable(
            channel_state.our_state,
            channel_state.partner_state,
        )
        assert distributable == TEST_DEPOSIT_AMOUNT
        assert distributable == channel_state.our_state.contract_balance
        assert channel.get_status(channel_state) == CHANNEL_STATE_OPENED

        # Run API test
        run_restapi_smoketests()
    except Exception:
        error = traceback.format_exc()
        if debug:
            import pdb
            pdb.post_mortem()  # pylint: disable=no-member
        return error
Example #57
0
    def channel_batch_close(
            self,
            registry_address: typing.PaymentNetworkID,
            token_address: typing.TokenAddress,
            partner_addresses: typing.List[typing.Address],
            retry_timeout: typing.NetworkTimeout = DEFAULT_RETRY_TIMEOUT,
    ):
        """Close a channel opened with `partner_address` for the given
        `token_address`.

        Race condition, this can fail if channel was closed externally.
        """

        if not is_binary_address(token_address):
            raise InvalidAddress('Expected binary address format for token in channel close')

        if not all(map(is_binary_address, partner_addresses)):
            raise InvalidAddress('Expected binary address format for partner in channel close')

        valid_tokens = views.get_token_network_addresses_for(
            views.state_from_raiden(self.raiden),
            registry_address,
        )
        if token_address not in valid_tokens:
            raise UnknownTokenAddress('Token address is not known.')

        chain_state = views.state_from_raiden(self.raiden)
        channels_to_close = views.filter_channels_by_partneraddress(
            chain_state,
            registry_address,
            token_address,
            partner_addresses,
        )
        token_network_identifier = views.get_token_network_identifier_by_token_address(
            views.state_from_raiden(self.raiden),
            registry_address,
            token_address,
        )

        # If concurrent operations are happening on one of the channels, fail entire
        # request.
        with ExitStack() as stack:
            # Put all the locks in this outer context so that the netting channel functions
            # don't release the locks when their context goes out of scope
            for channel_state in channels_to_close:
                channel = self.raiden.chain.payment_channel(
                    token_network_identifier,
                    channel_state.identifier,
                )
                stack.enter_context(channel.lock_or_raise())

            for channel_state in channels_to_close:
                channel_close = ActionChannelClose(
                    token_network_identifier,
                    channel_state.identifier,
                )

                self.raiden.handle_state_change(channel_close)

        channel_ids = [channel_state.identifier for channel_state in channels_to_close]

        waiting.wait_for_close(
            self.raiden,
            registry_address,
            token_address,
            channel_ids,
            retry_timeout,
        )
Example #58
0
    def start(self):
        """ Start the node. """
        if self.stop_event and self.stop_event.is_set():
            self.stop_event.clear()

        if self.database_dir is not None:
            self.db_lock.acquire(timeout=0)
            assert self.db_lock.is_locked

        # The database may be :memory:
        storage = sqlite.SQLiteStorage(self.database_path,
                                       serialize.PickleSerializer())
        self.wal, unapplied_events = wal.restore_from_latest_snapshot(
            node.state_transition,
            storage,
        )

        last_log_block_number = None
        # First run, initialize the basic state
        if self.wal.state_manager.current_state is None:
            block_number = self.chain.block_number()

            state_change = ActionInitNode(
                random.Random(),
                block_number,
            )
            self.wal.log_and_dispatch(state_change, block_number)
        else:
            # Get the last known block number after reapplying all the state changes from the log
            last_log_block_number = views.block_number(
                self.wal.state_manager.current_state)

        # The alarm task must be started after the snapshot is loaded or the
        # state is primed, the callbacks assume the node is initialized.
        self.alarm.start()
        self.alarm.register_callback(self.poll_blockchain_events)
        self.alarm.register_callback(self.set_block_number)
        self._block_number = self.chain.block_number()

        # Registry registration must start *after* the alarm task. This
        # avoids corner cases where the registry is queried in block A, a new
        # block B is mined, and the alarm starts polling at block C.

        # If last_log_block_number is None, the wal.state_manager.current_state was
        # None in the log, meaning we don't have any events we care about, so just
        # read the latest state from the network
        self.register_payment_network(self.default_registry.address,
                                      last_log_block_number)

        # Start the protocol after the registry is queried to avoid warning
        # about unknown channels.
        queueids_to_queues = views.get_all_messagequeues(
            views.state_from_raiden(self))

        # TODO: remove the cyclic dependency between the protocol and this instance
        self.protocol.start(self, queueids_to_queues)

        # Health check needs the protocol layer
        self.start_neighbours_healthcheck()

        for event in unapplied_events:
            on_raiden_event(self, event)

        self.start_event.set()
Example #59
0
    def set_total_channel_deposit(
        self,
        registry_address: TokenNetworkRegistryAddress,
        token_address: TokenAddress,
        partner_address: Address,
        total_deposit: TokenAmount,
        retry_timeout: NetworkTimeout = DEFAULT_RETRY_TIMEOUT,
    ) -> None:
        """ Set the `total_deposit` in the channel with the peer at `partner_address` and the
        given `token_address` in order to be able to do transfers.

        Raises:
            InvalidBinaryAddress: If either token_address or partner_address is not
                20 bytes long.
            RaidenRecoverableError: May happen for multiple reasons:
                - If the token approval fails, e.g. the token may validate if
                account has enough balance for the allowance.
                - The deposit failed, e.g. the allowance did not set the token
                aside for use and the user spent it before deposit was called.
                - The channel was closed/settled between the allowance call and
                the deposit call.
            AddressWithoutCode: The channel was settled during the deposit
                execution.
            DepositOverLimit: The total deposit amount is higher than the limit.
            UnexpectedChannelState: The channel is no longer in an open state.
        """
        chain_state = views.state_from_raiden(self.raiden)

        token_addresses = views.get_token_identifiers(chain_state,
                                                      registry_address)
        channel_state = views.get_channelstate_for(
            chain_state=chain_state,
            token_network_registry_address=registry_address,
            token_address=token_address,
            partner_address=partner_address,
        )

        if not is_binary_address(token_address):
            raise InvalidBinaryAddress(
                "Expected binary address format for token in channel deposit")

        if not is_binary_address(partner_address):
            raise InvalidBinaryAddress(
                "Expected binary address format for partner in channel deposit"
            )

        if token_address not in token_addresses:
            raise UnknownTokenAddress("Unknown token address")

        if channel_state is None:
            raise NonexistingChannel(
                "No channel with partner_address for the given token")

        confirmed_block_identifier = chain_state.block_hash
        token = self.raiden.proxy_manager.token(
            token_address, block_identifier=confirmed_block_identifier)
        token_network_registry = self.raiden.proxy_manager.token_network_registry(
            registry_address, block_identifier=confirmed_block_identifier)
        token_network_address = token_network_registry.get_token_network(
            token_address=token_address,
            block_identifier=confirmed_block_identifier)

        if token_network_address is None:
            raise UnknownTokenAddress(
                f"Token {to_checksum_address(token_address)} is not registered "
                f"with the network {to_checksum_address(registry_address)}.")

        token_network_proxy = self.raiden.proxy_manager.token_network(
            address=token_network_address,
            block_identifier=confirmed_block_identifier)
        channel_proxy = self.raiden.proxy_manager.payment_channel(
            channel_state=channel_state,
            block_identifier=confirmed_block_identifier)

        blockhash = chain_state.block_hash
        token_network_proxy = channel_proxy.token_network

        safety_deprecation_switch = token_network_proxy.safety_deprecation_switch(
            block_identifier=blockhash)

        balance = token.balance_of(self.raiden.address,
                                   block_identifier=blockhash)

        network_balance = token.balance_of(
            address=Address(token_network_address), block_identifier=blockhash)
        token_network_deposit_limit = token_network_proxy.token_network_deposit_limit(
            block_identifier=blockhash)

        addendum = total_deposit - channel_state.our_state.contract_balance

        channel_participant_deposit_limit = token_network_proxy.channel_participant_deposit_limit(
            block_identifier=blockhash)
        total_channel_deposit = total_deposit + channel_state.partner_state.contract_balance

        is_channel_open = channel.get_status(
            channel_state) == ChannelState.STATE_OPENED

        if not is_channel_open:
            raise UnexpectedChannelState("Channel is not in an open state.")

        if safety_deprecation_switch:
            msg = ("This token_network has been deprecated. "
                   "All channels in this network should be closed and "
                   "the usage of the newly deployed token network contract "
                   "is highly encouraged.")
            raise TokenNetworkDeprecated(msg)

        if total_deposit <= channel_state.our_state.contract_balance:
            raise DepositMismatch("Total deposit did not increase.")

        # If this check succeeds it does not imply the `deposit` will
        # succeed, since the `deposit` transaction may race with another
        # transaction.
        if not (balance >= addendum):
            msg = "Not enough balance to deposit. {} Available={} Needed={}".format(
                to_checksum_address(token_address), balance, addendum)
            raise InsufficientFunds(msg)

        if network_balance + addendum > token_network_deposit_limit:
            msg = f"Deposit of {addendum} would have exceeded the token network deposit limit."
            raise DepositOverLimit(msg)

        if total_deposit > channel_participant_deposit_limit:
            msg = (f"Deposit of {total_deposit} is larger than the "
                   f"channel participant deposit limit")
            raise DepositOverLimit(msg)

        if total_channel_deposit >= UINT256_MAX:
            raise DepositOverLimit("Deposit overflow")

        try:
            channel_proxy.approve_and_set_total_deposit(
                total_deposit=total_deposit, block_identifier=blockhash)
        except RaidenRecoverableError as e:
            log.info(f"Deposit failed. {str(e)}")

        target_address = self.raiden.address
        waiting.wait_for_participant_deposit(
            raiden=self.raiden,
            token_network_registry_address=registry_address,
            token_address=token_address,
            partner_address=partner_address,
            target_address=target_address,
            target_balance=total_deposit,
            retry_timeout=retry_timeout,
        )
Example #60
0
def test_lock_expiry(raiden_network, token_addresses, deposit):
    """Test lock expiry and removal."""
    alice_app, bob_app = raiden_network
    token_address = token_addresses[0]
    token_network_address = views.get_token_network_address_by_token_address(
        views.state_from_app(alice_app),
        alice_app.raiden.default_registry.address, token_address)
    assert token_network_address

    hold_event_handler = bob_app.raiden.raiden_event_handler
    wait_message_handler = bob_app.raiden.message_handler

    token_network = views.get_token_network_by_address(
        views.state_from_app(alice_app), token_network_address)
    assert token_network

    channel_state = get_channelstate(alice_app, bob_app, token_network_address)
    channel_identifier = channel_state.identifier

    assert (channel_identifier
            in token_network.partneraddresses_to_channelidentifiers[
                bob_app.raiden.address])

    alice_to_bob_amount = 10
    identifier = 1
    target = bob_app.raiden.address
    transfer_1_secret = factories.make_secret(0)
    transfer_1_secrethash = sha256_secrethash(transfer_1_secret)
    transfer_2_secret = factories.make_secret(1)
    transfer_2_secrethash = sha256_secrethash(transfer_2_secret)

    hold_event_handler.hold_secretrequest_for(secrethash=transfer_1_secrethash)
    transfer1_received = wait_message_handler.wait_for_message(
        LockedTransfer, {"lock": {
            "secrethash": transfer_1_secrethash
        }})
    transfer2_received = wait_message_handler.wait_for_message(
        LockedTransfer, {"lock": {
            "secrethash": transfer_2_secrethash
        }})
    remove_expired_lock_received = wait_message_handler.wait_for_message(
        LockExpired, {"secrethash": transfer_1_secrethash})

    alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=target,
        identifier=identifier,
        secret=transfer_1_secret,
    )
    transfer1_received.wait()

    alice_bob_channel_state = get_channelstate(alice_app, bob_app,
                                               token_network_address)
    lock = channel.get_lock(alice_bob_channel_state.our_state,
                            transfer_1_secrethash)
    assert lock

    # This is the current state of the protocol:
    #
    #    A -> B LockedTransfer
    #    B -> A SecretRequest
    #    - protocol didn't continue
    assert_synced_channel_state(token_network_address, alice_app, deposit,
                                [lock], bob_app, deposit, [])

    # Verify lock is registered in both channel states
    alice_channel_state = get_channelstate(alice_app, bob_app,
                                           token_network_address)
    assert transfer_1_secrethash in alice_channel_state.our_state.secrethashes_to_lockedlocks

    bob_channel_state = get_channelstate(bob_app, alice_app,
                                         token_network_address)
    assert transfer_1_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks

    alice_chain_state = views.state_from_raiden(alice_app.raiden)
    assert transfer_1_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task

    remove_expired_lock_received.wait()

    alice_channel_state = get_channelstate(alice_app, bob_app,
                                           token_network_address)
    assert transfer_1_secrethash not in alice_channel_state.our_state.secrethashes_to_lockedlocks

    # Verify Bob received the message and processed the LockExpired message
    bob_channel_state = get_channelstate(bob_app, alice_app,
                                         token_network_address)
    assert transfer_1_secrethash not in bob_channel_state.partner_state.secrethashes_to_lockedlocks

    alice_chain_state = views.state_from_raiden(alice_app.raiden)
    assert transfer_1_secrethash not in alice_chain_state.payment_mapping.secrethashes_to_task

    # Make another transfer
    alice_to_bob_amount = 10
    identifier = 2

    hold_event_handler.hold_secretrequest_for(secrethash=transfer_2_secrethash)

    alice_app.raiden.start_mediated_transfer_with_secret(
        token_network_address=token_network_address,
        amount=alice_to_bob_amount,
        target=target,
        identifier=identifier,
        secret=transfer_2_secret,
    )
    transfer2_received.wait()

    # Make sure the other transfer still exists
    alice_chain_state = views.state_from_raiden(alice_app.raiden)
    assert transfer_2_secrethash in alice_chain_state.payment_mapping.secrethashes_to_task

    bob_channel_state = get_channelstate(bob_app, alice_app,
                                         token_network_address)
    assert transfer_2_secrethash in bob_channel_state.partner_state.secrethashes_to_lockedlocks