Esempio n. 1
0
    def start(self):
        """ Start the node. """
        # XXX Should this really be here? Or will start() never be called again
        # after stop() in the lifetime of Raiden apart from the tests? This is
        # at least at the moment prompted by tests/integration/test_transer.py
        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.
        self.protocol.start()

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

        self.start_event.set()

        for event in unapplied_events:
            on_raiden_event(self, event)
Esempio n. 2
0
    def cross_handle_recieved_locked_transfer(self, transfer, cross_id):
        self.start_health_check_for(transfer.initiator)
        state_change = target_init(transfer)

        block_number = self.get_block_number()

        event_list = self.wal.log_and_dispatch(state_change, block_number)

        for event in event_list:
            log.debug('RAIDEN EVENT',
                      node=pex(self.address),
                      raiden_event=event)

            if type(event) == SendSecretRequest:
                secret_request_message = message_from_sendevent(
                    event, self.address)
                self.sign(secret_request_message)

                cross_secret_request_message = CrossSecretRequest(
                    secret_request_message, cross_id)
                self.sign(cross_secret_request_message)

                self.transport.send_async(
                    event.recipient,
                    event.queue_name,
                    cross_secret_request_message,
                )
                continue
            on_raiden_event(self, event)

        return event_list
Esempio n. 3
0
    def handle_state_change(self, state_change):
        log.debug('STATE CHANGE',
                  node=pex(self.address),
                  state_change=state_change)

        # Take a snapshot every SNAPSHOT_BLOCK_COUNT
        # TODO: Gather more data about storage requirements
        # and update the value to specify how often we need
        # capturing a snapshot should take place
        block_number = self.get_block_number()
        new_snapshot_group = block_number // SNAPSHOT_BLOCK_COUNT
        if new_snapshot_group > self.snapshot_group:
            log.debug(f'Storing snapshot at block: {block_number}')
            self.wal.snapshot()
            self.snapshot_group = new_snapshot_group

        event_list = self.wal.log_and_dispatch(state_change)

        if self.dispatch_events_lock.locked():
            return []

        for event in event_list:
            log.debug('RAIDEN EVENT',
                      node=pex(self.address),
                      raiden_event=event)
            on_raiden_event(self, event)

        return event_list
Esempio n. 4
0
    def handle_cross_state_change(self,
                                  state_change,
                                  cross_id,
                                  secret,
                                  btc_amount,
                                  block_number=None):
        if block_number is None:
            block_number = self.get_block_number()

        event_list = self.wal.log_and_dispatch(state_change, block_number)

        row = self.wal.storage.get_lnd(1)
        macaroon = row[4]
        lnd_url = "https://{}/v1/invoices".format(self.config['lnd_address'])
        lnd_headers = {'Grpc-Metadata-macaroon': macaroon}
        lnd_r = base64.b64encode(secret)
        lnd_data = {
            'value': btc_amount,
            'r_preimage': lnd_r.decode('utf-8'),
            'type': "CROSS_CHAIN_INVOICE"
        }

        res = requests.post(lnd_url,
                            headers=lnd_headers,
                            data=json.dumps(lnd_data),
                            verify=False)

        res_json = res.json()
        lnd_r_hash = res_json['r_hash']
        lnd_payment_request = res_json['payment_request']
        print('send invoice succ, lnd_r_hash:', lnd_r_hash)

        for event in event_list:
            log.debug('RAIDEN EVENT',
                      node=pex(self.address),
                      raiden_event=event)

            if type(event) == SendLockedTransfer:
                locked_transfer_message = message_from_sendevent(
                    event, self.address)
                self.sign(locked_transfer_message)
                self.wal.storage.change_crosstransaction_r(
                    cross_id,
                    encode_hex(locked_transfer_message.lock.secrethash),
                    lnd_r_hash)
                tmp_r_hash = base64.b64decode(lnd_r_hash)
                raiden_r_hash = locked_transfer_message.lock.secrethash
                hex_r_hash = encode_hex(tmp_r_hash)
                lnd_string = bytes(lnd_payment_request, "utf-8")
                cross_transfer_message = CrossLockedTransfer(
                    locked_transfer_message, cross_id, lnd_string)
                self.sign(cross_transfer_message)
                self.transport.send_async(cross_transfer_message.recipient,
                                          bytes("456", 'utf-8'),
                                          cross_transfer_message)
                print('corss_message send ok')
                continue

            on_raiden_event(self, event)
Esempio n. 5
0
    def handle_state_change(self, state_change, block_number=None):
        log.debug('STATE CHANGE', node=pex(self.address), state_change=state_change)

        if block_number is None:
            block_number = self.get_block_number()

        event_list = self.wal.log_and_dispatch(state_change, block_number)

        for event in event_list:
            log.debug('EVENT', node=pex(self.address), raiden_event=event)

            on_raiden_event(self, event)

        return event_list
Esempio n. 6
0
    def handle_state_change(self, state_change, block_number=None):
        log.debug('STATE CHANGE', node=pex(self.address), state_change=state_change)

        if block_number is None:
            block_number = self.get_block_number()

        event_list = self.wal.log_and_dispatch(state_change, block_number)

        for event in event_list:
            log.debug('RAIDEN EVENT', node=pex(self.address), raiden_event=event)

            on_raiden_event(self, event)

        return event_list
Esempio n. 7
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,
        )

        if self.wal.state_manager.current_state is None:
            block_number = self.chain.block_number()

            state_change = ActionInitChain(
                random.Random(),
                block_number,
                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(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)

        # 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()

        self.alarm.start()

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

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

        for event in unapplied_events:
            on_raiden_event(self, event)

        self.start_event.set()
Esempio n. 8
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'],
            )

        # The database may be :memory:
        storage = sqlite.SQLiteStorage(self.database_path,
                                       serialize.JSONSerializer())
        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',
                node=pex(self.address),
            )
            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)
            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_HASH_BYTES,
                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,
                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}', )

        # Clear ref cache & disable caching
        serialize.RaidenJSONDecoder.ref_cache.clear()
        serialize.RaidenJSONDecoder.cache_object_references = False

        # 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),
            node=pex(self.address),
        )
        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)
        # repopulate identifier_to_results for pending transfers
        for queue_messages in queueids_to_queues.values():
            for message in queue_messages:
                if isinstance(message, SendDirectTransfer):
                    self.identifier_to_results[
                        message.payment_identifier] = AsyncResult()
        self.transport.start(self, queueids_to_queues)

        # 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()

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

        super().start()
Esempio n. 9
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,
        )

        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)

            # 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 = None
        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)

        # The time the alarm task is started or the callbacks are installed doesn't
        # really matter.
        #
        # But it is of paramount importance to:
        # - Install the filters which will be polled by poll_blockchain_events
        #   after the state has been primed, otherwise the state changes won't
        #   have effect.
        # - Install the filters using the correct from_block value, otherwise
        #   blockchain logs can be lost.
        self.alarm.register_callback(self._callback_new_block)
        self.alarm.start()

        self.install_payment_network_filters(
            self.default_registry.address,
            last_log_block_number,
        )

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

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

        for event in unapplied_events:
            on_raiden_event(self, event)

        self.start_event.set()
Esempio n. 10
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
Esempio n. 11
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,
        )

        if self.wal.state_manager.current_state is None:
            block_number = self.chain.block_number()

            state_change = ActionInitChain(
                random.Random(),
                block_number,
                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(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)

        # 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()

        self.alarm.start()

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

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

        for event in unapplied_events:
            on_raiden_event(self, event)

        self.start_event.set()