Exemple #1
0
class RaidenService(object):  # pylint: disable=too-many-instance-attributes
    """ A Raiden node. """

    def __init__(self, chain, privkey, transport, discovery, config):  # pylint: disable=too-many-arguments
        self.registries = list()
        self.managers_by_asset_address = dict()
        self.managers_by_address = dict()
        self.event_listeners = list()

        self.chain = chain
        self.config = config
        self.privkey = privkey
        self.address = privtoaddr(privkey)
        self.protocol = RaidenProtocol(transport, discovery, self)
        transport.protocol = self.protocol

        message_handler = RaidenMessageHandler(self)
        event_handler = RaidenEventHandler(self)

        self.api = RaidenAPI(self)
        self.event_handler = event_handler
        self.message_handler = message_handler

        self.on_message = message_handler.on_message
        self.on_event = event_handler.on_event

    def __repr__(self):
        return '<{} {}>'.format(self.__class__.__name__, pex(self.address))

    def get_manager_by_asset_address(self, asset_address_bin):
        """ Return the manager for the given `asset_address_bin`.  """
        return self.managers_by_asset_address[asset_address_bin]

    def get_manager_by_address(self, manager_address_bin):
        return self.managers_by_address[manager_address_bin]

    def find_channel_by_address(self, netting_channel_address_bin):
        for manager in self.managers_by_address.itervalues():
            channel = manager.address_channel.get(netting_channel_address_bin)

            if channel is not None:
                return channel

        raise ValueError('unknow channel {}'.format(encode_hex(netting_channel_address_bin)))

    def sign(self, message):
        """ Sign message inplace. """
        if not isinstance(message, SignedMessage):
            raise ValueError('{} is not signable.'.format(repr(message)))

        message.sign(self.privkey)

    def send(self, recipient, message):
        """ Send `message` to `recipient` using the raiden protocol.

        The protocol will take care of resending the message on a given
        interval until an Acknowledgment is received or a given number of
        tries.
        """

        if not isaddress(recipient):
            raise ValueError('recipient is not a valid address.')

        self.protocol.send(recipient, message)

    def send_and_wait(self, recipient, message, timeout, event):
        """ Send `message` to `recipient` and wait for the response or `timeout`.

        Args:
            recipient (address): The address of the node that will receive the
                message.
            message: The transfer message.
            timeout (float): How long should we wait for a response from `recipient`.
            event (gevent.event.AsyncResult): Event that will receive the result.

        Returns:
            None: If the wait timed out
            object: The result from the event
        """
        self.send(recipient, message)
        return event.wait(timeout)

    def message_for_task(self, message, hashlock):
        """ Sends the message to the corresponding task.

        The corresponding task is found by matching the hashlock.

        Return:
            bool: True if a correspoding task is found, False otherwise.
        """
        for asset_manager in self.managers_by_asset_address.values():
            task = asset_manager.transfermanager.transfertasks.get(hashlock)

            if task is not None:
                task.on_event(message)
                return True

        return False

    def register_registry(self, registry):
        """ Register the registry and intialize all the related assets and
        channels.
        """
        translator = ContractTranslator(REGISTRY_ABI)

        assetadded = registry.assetadded_filter()

        all_manager_addresses = registry.manager_addresses()

        asset_listener = LogListenerTask(
            assetadded,
            self.on_event,
            translator,
        )
        asset_listener.start()
        self.event_listeners.append(asset_listener)

        self.registries.append(registry)

        for manager_address in all_manager_addresses:
            channel_manager = self.chain.manager(manager_address)
            self.register_channel_manager(channel_manager)

    def register_channel_manager(self, channel_manager):
        """ Discover and register the channels for the given asset. """
        translator = ContractTranslator(CHANNEL_MANAGER_ABI)

        # To avoid missing changes, first create the filter, call the
        # contract and then start polling.
        channelnew = channel_manager.channelnew_filter(self.address)

        all_netting_contracts = channel_manager.channels_by_participant(self.address)

        channel_listener = LogListenerTask(
            channelnew,
            self.on_event,
            translator,
        )
        channel_listener.start()
        self.event_listeners.append(channel_listener)

        asset_address_bin = channel_manager.asset_address()
        channel_manager_address_bin = channel_manager.address
        edges = channel_manager.channels_addresses()
        channel_graph = ChannelGraph(edges)

        asset_manager = AssetManager(
            self,
            asset_address_bin,
            channel_manager_address_bin,
            channel_graph,
        )
        self.managers_by_asset_address[asset_address_bin] = asset_manager
        self.managers_by_address[channel_manager_address_bin] = asset_manager

        for netting_contract_address in all_netting_contracts:
            asset_manager.register_channel_by_address(
                netting_contract_address,
                self.config['reveal_timeout'],
            )

    def stop(self):
        for listener in self.event_listeners:
            listener.stop_event.set(True)
            self.chain.uninstall_filter(listener.filter_.filter_id_raw)
Exemple #2
0
class RaidenService(object):
    """ Runs a service on a node """

    def __init__(self, chain, privkey, transport, discovery, config):  # pylint: disable=too-many-arguments
        self.chain = chain
        self.config = config
        self.privkey = privkey
        self.address = privtoaddr(privkey)
        self.protocol = RaidenProtocol(transport, discovery, self)
        transport.protocol = self.protocol
        self.assetmanagers = dict()
        self.api = RaidenAPI(self)

    def __repr__(self):
        return '<{} {}>'.format(self.__class__.__name__, pex(self.address))

    def setup_asset(self, asset_address, reveal_timeout):
        """ Initialize a `AssetManager`, and for each open channel that this
        node has create a corresponding `Channel`.

        Args:
            asset_address (address): A list of asset addresses that need to
                be considered.
            reveal_timeout (int): Minimum number of blocks required for the
                settling of a netting contract.
        """
        netting_address = self.chain.nettingaddresses_by_asset_participant(
            asset_address,
            self.address,
        )

        asset_manager = self.get_or_create_asset_manager(asset_address)

        for nettingcontract_address in netting_address:
            self.setup_channel(
                asset_manager,
                asset_address,
                nettingcontract_address,
                reveal_timeout,
            )

    def get_or_create_asset_manager(self, asset_address):
        """ Return the AssetManager for the given `asset_address`. """
        if asset_address not in self.assetmanagers:
            edges = self.chain.addresses_by_asset(asset_address)
            channel_graph = ChannelGraph(edges)

            asset_manager = AssetManager(self, asset_address, channel_graph)
            self.assetmanagers[asset_address] = asset_manager

        return self.assetmanagers[asset_address]

    def setup_channel(self, asset_manager, asset_address, nettingcontract_address, reveal_timeout):
        """ Initialize the Channel for the given netting contract. """

        channel_details = self.chain.netting_contract_detail(
            asset_address,
            nettingcontract_address,
            self.address,
        )

        our_state = ChannelEndState(
            self.address,
            channel_details['our_balance'],
        )

        partner_state = ChannelEndState(
            channel_details['partner_address'],
            channel_details['partner_balance'],
        )

        channel = Channel(
            self.chain,
            asset_address,
            nettingcontract_address,
            our_state,
            partner_state,
            reveal_timeout,
        )

        asset_manager.add_channel(channel_details['partner_address'], channel)

    def has_path(self, asset, target):
        if asset not in self.assetmanagers:
            return False

        graph = self.assetmanagers[asset].channelgraph
        return graph.has_path(self.address, target)

    def sign(self, msg):
        assert isinstance(msg, messages.SignedMessage)
        return msg.sign(self.privkey)

    def on_message(self, msg, msghash):
        log.debug('ON MESSAGE {} {}'.format(pex(self.address), msg))
        method = 'on_%s' % msg.__class__.__name__.lower()
        # update activity monitor (which also does pings to all addresses in channels)
        getattr(self, method)(msg)
        self.protocol.send_ack(msg.sender, messages.Ack(self.address, msghash))

    def on_message_failsafe(self, msg, msghash):
        method = 'on_%s' % msg.__class__.__name__.lower()
        # update activity monitor (which also does pings to all addresses in channels)
        try:
            getattr(self, method)(msg)
        except messages.BaseError as error:
            self.protocol.send_ack(msg.sender, error)
        else:
            self.protocol.send_ack(msg.sender, messages.Ack(self.address, msghash))

    def send(self, recipient, msg):
        # assert msg.sender
        assert isaddress(recipient)
        self.protocol.send(recipient, msg)

    def on_baseerror(self, msg):
        pass

    def on_ping(self, msg):
        pass  # ack already sent, activity monitor should have been notified in on_message

    def on_transfer(self, msg):
        asset_manager = self.assetmanagers[msg.asset]
        asset_manager.transfermanager.on_transfer(msg)

    on_lockedtransfer = on_directtransfer = on_transfer

    def on_mediatedtransfer(self, msg):
        asset_manager = self.assetmanagers[msg.asset]
        asset_manager.transfermanager.on_mediatedtransfer(msg)

    # events, that need to find a TransferTask

    def on_event_for_transfertask(self, msg):
        if isinstance(msg, messages.LockedTransfer):
            hashlock = msg.lock.hashlock
        else:
            # TransferTimeout, Secret, SecretRequest, ConfirmTransfer
            hashlock = msg.hashlock

        for asset_manager in self.assetmanagers.values():
            if hashlock in asset_manager.transfermanager.transfertasks:
                asset_manager.transfermanager.transfertasks[hashlock].on_event(msg)
                return True

    on_secretrequest = on_transfertimeout = on_canceltransfer = on_event_for_transfertask

    def on_secret(self, msg):
        self.on_event_for_transfertask(msg)
        for asset_manager in self.assetmanagers.values():
            asset_manager.on_secret(msg)

    def on_transferrequest(self, msg):
        asset_manager = self.assetmanagers[msg.asset]
        asset_manager.transfermanager.on_tranferrequest(msg)

    # other

    def on_rejected(self, msg):
        pass

    def on_hashlockrequest(self, msg):
        pass

    def on_exchangerequest(self, msg):
        pass
Exemple #3
0
class RaidenService(object):
    """ Runs a service on a node """
    def __init__(self, chain, privkey, transport, discovery):
        self.chain = chain
        self.privkey = privkey
        self.address = privtoaddr(privkey)
        self.protocol = RaidenProtocol(transport, discovery, self)
        transport.protocol = self.protocol
        self.assetmanagers = dict()
        self.api = RaidenAPI(self)

    def __repr__(self):
        return '<{} {}>'.format(self.__class__.__name__, pex(self.address))

    def setup_asset(self, asset_address, min_locktime):
        """ Initialize a `AssetManager`, and for each open channel that this
        node has create a corresponding `Channel`.

        Args:
            asset_address (address): A list of asset addresses that need to
                be considered.
            min_locktime (int): Minimum number of blocks required for the
                settling of a netting contract.
        """
        netting_address = self.chain.nettingaddresses_by_asset_participant(
            asset_address,
            self.address,
        )

        asset_manager = self.get_or_create_asset_manager(asset_address)

        for nettingcontract_address in netting_address:
            self.setup_channel(
                asset_manager,
                asset_address,
                nettingcontract_address,
                min_locktime,
            )

    def get_or_create_asset_manager(self, asset_address):
        """ Return the AssetManager for the given `asset_address`. """
        if asset_address not in self.assetmanagers:
            edges = self.chain.addresses_by_asset(asset_address)
            channel_graph = ChannelGraph(edges)

            asset_manager = AssetManager(self, asset_address, channel_graph)
            self.assetmanagers[asset_address] = asset_manager

        return self.assetmanagers[asset_address]

    def setup_channel(self, asset_manager, asset_address,
                      nettingcontract_address, min_locktime):
        """ Initialize the Channel for the given netting contract. """

        channel_details = self.chain.netting_contract_detail(
            asset_address,
            nettingcontract_address,
            self.address,
        )

        our_state = ChannelEndState(
            self.address,
            channel_details['our_balance'],
        )

        partner_state = ChannelEndState(
            channel_details['partner_address'],
            channel_details['partner_balance'],
        )

        channel = Channel(
            self.chain,
            asset_address,
            nettingcontract_address,
            our_state,
            partner_state,
            min_locktime=min_locktime,
        )

        asset_manager.add_channel(channel_details['partner_address'], channel)

    def has_path(self, asset, target):
        assetmanager = self.assetmanagers.get(asset)
        if assetmanager is not None:
            channel = assetmanager.channelgraph.graph
            if target in channel.nodes():
                return nx.has_path(channel, self.address, target)
        return False

    def sign(self, msg):
        assert isinstance(msg, messages.SignedMessage)
        return msg.sign(self.privkey)

    def on_message(self, msg, msghash):
        log.debug('ON MESSAGE {} {}'.format(pex(self.address), msg))
        method = 'on_%s' % msg.__class__.__name__.lower()
        # update activity monitor (which also does pings to all addresses in channels)
        getattr(self, method)(msg)
        self.protocol.send_ack(msg.sender, messages.Ack(self.address, msghash))

    def on_message_failsafe(self, msg, msghash):
        method = 'on_%s' % msg.__class__.__name__.lower()
        # update activity monitor (which also does pings to all addresses in channels)
        try:
            getattr(self, method)(msg)
        except messages.BaseError as error:
            self.protocol.send_ack(msg.sender, error)
        else:
            self.protocol.send_ack(msg.sender,
                                   messages.Ack(self.address, msghash))

    def send(self, recipient, msg):
        # assert msg.sender
        assert isaddress(recipient)
        self.protocol.send(recipient, msg)

    def on_baseerror(self, msg):
        pass

    def on_ping(self, msg):
        pass  # ack already sent, activity monitor should have been notified in on_message

    def on_transfer(self, msg):
        asset_manager = self.assetmanagers[msg.asset]
        asset_manager.transfermanager.on_transfer(msg)

    on_lockedtransfer = on_directtransfer = on_transfer

    def on_mediatedtransfer(self, msg):
        asset_manager = self.assetmanagers[msg.asset]
        asset_manager.transfermanager.on_mediatedtransfer(msg)

    # events, that need to find a TransferTask

    def on_event_for_transfertask(self, msg):
        if isinstance(msg, messages.LockedTransfer):
            hashlock = msg.lock.hashlock
        else:
            # TransferTimeout, Secret, SecretRequest, ConfirmTransfer
            hashlock = msg.hashlock

        for asset_manager in self.assetmanagers.values():
            if hashlock in asset_manager.transfermanager.transfertasks:
                asset_manager.transfermanager.transfertasks[hashlock].on_event(
                    msg)
                return True

    on_secretrequest = on_transfertimeout = on_canceltransfer = on_event_for_transfertask

    def on_secret(self, msg):
        self.on_event_for_transfertask(msg)
        for asset_manager in self.assetmanagers.values():
            asset_manager.on_secret(msg)

    def on_transferrequest(self, msg):
        asset_manager = self.assetmanagers[msg.asset]
        asset_manager.transfermanager.on_tranferrequest(msg)

    # other

    def on_rejected(self, msg):
        pass

    def on_hashlockrequest(self, msg):
        pass

    def on_exchangerequest(self, msg):
        pass
Exemple #4
0
class RaidenService(object):  # pylint: disable=too-many-instance-attributes
    """ A Raiden node. """
    def __init__(self, chain, privkey, transport, discovery, config):  # pylint: disable=too-many-arguments
        self.registries = list()
        self.managers_by_asset_address = dict()
        self.managers_by_address = dict()
        self.event_listeners = list()

        self.chain = chain
        self.config = config
        self.privkey = privkey
        self.address = privtoaddr(privkey)
        self.protocol = RaidenProtocol(transport, discovery, self)
        transport.protocol = self.protocol

        message_handler = RaidenMessageHandler(self)
        event_handler = RaidenEventHandler(self)

        self.api = RaidenAPI(self)
        self.event_handler = event_handler
        self.message_handler = message_handler

        self.on_message = message_handler.on_message
        self.on_event = event_handler.on_event

    def __repr__(self):
        return '<{} {}>'.format(self.__class__.__name__, pex(self.address))

    def get_manager_by_asset_address(self, asset_address_bin):
        """ Return the manager for the given `asset_address_bin`.  """
        return self.managers_by_asset_address[asset_address_bin]

    def get_manager_by_address(self, manager_address_bin):
        return self.managers_by_address[manager_address_bin]

    def find_channel_by_address(self, netting_channel_address_bin):
        for manager in self.managers_by_address.itervalues():
            channel = manager.address_channel.get(netting_channel_address_bin)

            if channel is not None:
                return channel

        raise ValueError('unknow channel {}'.format(
            encode_hex(netting_channel_address_bin)))

    def sign(self, message):
        """ Sign message inplace. """
        if not isinstance(message, SignedMessage):
            raise ValueError('{} is not signable.'.format(repr(message)))

        message.sign(self.privkey)

    def send(self, recipient, message):
        """ Send `message` to `recipient` using the raiden protocol.

        The protocol will take care of resending the message on a given
        interval until an Acknowledgment is received or a given number of
        tries.
        """

        if not isaddress(recipient):
            raise ValueError('recipient is not a valid address.')

        self.protocol.send(recipient, message)

    def send_and_wait(self, recipient, message, timeout, event):
        """ Send `message` to `recipient` and wait for the response or `timeout`.

        Args:
            recipient (address): The address of the node that will receive the
                message.
            message: The transfer message.
            timeout (float): How long should we wait for a response from `recipient`.
            event (gevent.event.AsyncResult): Event that will receive the result.

        Returns:
            None: If the wait timed out
            object: The result from the event
        """
        self.send(recipient, message)
        return event.wait(timeout)

    def message_for_task(self, message, hashlock):
        """ Sends the message to the corresponding task.

        The corresponding task is found by matching the hashlock.

        Return:
            bool: True if a correspoding task is found, False otherwise.
        """
        for asset_manager in self.managers_by_asset_address.values():
            task = asset_manager.transfermanager.transfertasks.get(hashlock)

            if task is not None:
                task.on_event(message)
                return True

        return False

    def register_registry(self, registry):
        """ Register the registry and intialize all the related assets and
        channels.
        """
        translator = ContractTranslator(REGISTRY_ABI)

        assetadded = registry.assetadded_filter()

        all_manager_addresses = registry.manager_addresses()

        asset_listener = LogListenerTask(
            assetadded,
            self.on_event,
            translator,
        )
        asset_listener.start()
        self.event_listeners.append(asset_listener)

        self.registries.append(registry)

        for manager_address in all_manager_addresses:
            channel_manager = self.chain.manager(manager_address)
            self.register_channel_manager(channel_manager)

    def register_channel_manager(self, channel_manager):
        """ Discover and register the channels for the given asset. """
        translator = ContractTranslator(CHANNEL_MANAGER_ABI)

        # To avoid missing changes, first create the filter, call the
        # contract and then start polling.
        channelnew = channel_manager.channelnew_filter(self.address)

        all_netting_contracts = channel_manager.channels_by_participant(
            self.address)

        channel_listener = LogListenerTask(
            channelnew,
            self.on_event,
            translator,
        )
        channel_listener.start()
        self.event_listeners.append(channel_listener)

        asset_address_bin = channel_manager.asset_address()
        channel_manager_address_bin = channel_manager.address
        edges = channel_manager.channels_addresses()
        channel_graph = ChannelGraph(edges)

        asset_manager = AssetManager(
            self,
            asset_address_bin,
            channel_manager_address_bin,
            channel_graph,
        )
        self.managers_by_asset_address[asset_address_bin] = asset_manager
        self.managers_by_address[channel_manager_address_bin] = asset_manager

        for netting_contract_address in all_netting_contracts:
            asset_manager.register_channel_by_address(
                netting_contract_address,
                self.config['reveal_timeout'],
            )

    def stop(self):
        for listener in self.event_listeners:
            listener.stop_event.set(True)
            self.chain.uninstall_filter(listener.filter_.filter_id_raw)