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), )
def wait_for_block( raiden: RaidenService, block_number: typing.BlockNumber, poll_timeout: typing.NetworkTimeout, ) -> None: current_block_number = views.block_number( views.state_from_raiden(raiden), ) while current_block_number < block_number: gevent.sleep(poll_timeout) current_block_number = views.block_number( views.state_from_raiden(raiden), )
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), )
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)
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), ) 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.EMPTY_HASH, 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 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 avoid rejecting messages for unknown channels. self.alarm.register_callback(self._callback_new_block) # alarm.first_run may process some new channel, which would start_health_check_for # a partner, that's why transport needs to be already started at this point self.transport.start(self) 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: try: self.raiden_event_handler.on_raiden_event( self, transaction) except RaidenRecoverableError as e: log.error(str(e)) except RaidenUnrecoverableError as e: if self.config['network_type'] == NetworkType.MAIN: if isinstance(e, InvalidDBData): raise log.error(str(e)) else: raise self.alarm.start() # after transport and alarm is started, send queued messages events_queues = views.get_all_messagequeues(chain_state) for queue_identifier, event_queue in events_queues.items(): self.start_health_check_for(queue_identifier.recipient) # repopulate identifier_to_results for pending transfers for event in event_queue: if type(event) == SendDirectTransfer: self.identifier_to_results[ event.payment_identifier] = AsyncResult() message = message_from_sendevent(event, self.address) self.sign(message) self.transport.send_async(queue_identifier, message) # 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()
def get_block_number(self) -> BlockNumber: assert self.wal return views.block_number(self.wal.state_manager.current_state)
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'], ) self.maybe_upgrade_db() storage = sqlite.SerializedSQLiteStorage( database_path=self.database_path, serializer=serialize.JSONSerializer(), ) storage.log_run() 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) with self.dispatch_events_lock: 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) self._initialize_payment_statuses(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( raiden_service=self, message_handler=self.message_handler, prev_auth_data=chain_state.last_transport_authdata, ) # 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 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()
def assert_deposit( token_network_address: TokenNetworkAddress, app0: App, app1: App, saved_state0: SavedState, saved_state1: SavedState, ) -> None: """Assert that app0 and app1 agree on app0's on-chain deposit. Notes: - This does not check the deposit from app1. It can be done with a second call to the function. - The two apps don't have to be at the same view of the blockchain, i.e. app1 may have seen the latest block but app0 not. - It is important to do the validation on a fixed state, that is why saved_state0 is used. """ # Do not assert on the block number themselves, only useful to clarify the # error messages block_number0 = views.block_number(saved_state0.state) block_number1 = views.block_number(saved_state1.state) channel0 = views.get_channelstate_by_token_network_and_partner( saved_state0.state, token_network_address, app1.raiden.address) channel1 = views.get_channelstate_by_token_network_and_partner( saved_state1.state, token_network_address, app0.raiden.address) assert channel0 assert channel1 if channel0.our_state.contract_balance != channel1.partner_state.contract_balance: # TODO: Only consider the records up to saved state's state_change_id. # ATM this has a race condition where this utility could be called # before the alarm task fetches the corresponding event but while it # runs it does fetch it. # Any of the nodes may have seen the deposit first contract_balance = max(channel0.our_state.contract_balance, channel1.partner_state.contract_balance) deposit_description = { "canonical_identifier": { "chain_identifier": channel0.canonical_identifier.chain_identifier, "token_network_address": channel0.canonical_identifier.token_network_address, "channel_identifier": channel0.canonical_identifier.channel_identifier, }, "deposit_transaction": { "participant_address": channel0.our_state.address, "contract_balance": contract_balance, }, } node0_deposit_event = raiden_state_changes_search_for_item( app0.raiden, ContractReceiveChannelDeposit, deposit_description) node1_deposit_event = raiden_state_changes_search_for_item( app1.raiden, ContractReceiveChannelDeposit, deposit_description) is_partner_deposit_ignored = ( node1_deposit_event is not None and channel1.partner_state.contract_balance != contract_balance) is_self_deposit_ignored = ( node0_deposit_event is not None and channel0.partner_state.contract_balance != contract_balance) is_partner_deposit_missed = ( node0_deposit_event and node0_deposit_event.deposit_transaction.deposit_block_number >= block_number1) is_self_deposit_missed = ( node1_deposit_event and node1_deposit_event.deposit_transaction.deposit_block_number >= block_number1) if is_self_deposit_ignored: msg = "Node0 has fetched and ignored the its deposits, this is likely a bug." elif is_partner_deposit_ignored: msg = "Node1 has fetched and ignored the node0's deposits, this is likely a bug." elif is_self_deposit_missed: msg = ( "Node0's has a problem with its blockchain event filters, it " "has not seen its deposit event even though it has seen a newer " "confirmed block") elif is_partner_deposit_missed: msg = ( "Node1's has a problem with its blockchain event filters, it " "missed node0's deposit event even though it has seen a newer " "confirmed block") elif not app1.raiden.alarm: msg = ( "Node1 has not seen the block at which node0's deposit happened " "and the alarm task is not running. Either the test stopped " "the node before it had time or the node got killed because of " "another error.") elif not app0.raiden.alarm: msg = ( "Node0 has not seen the block at which node0's deposit happened " "and the alarm task is not running. Either the test stopped " "the node before it had time or the node got killed because of " "another error.") elif channel0.our_state.contract_balance > channel1.partner_state.contract_balance: msg = ("Node1 has not yet seen the block at which node0's deposit " "happened. The test is likely missing synchronization.") elif channel1.our_state.contract_balance > channel0.partner_state.contract_balance: msg = ("Node0 has not yet seen the block at which its deposit " "happened. The test is likely missing synchronization.") else: raise RuntimeError( "This should never happen, the checks above are complementary") msg = (f"{msg}. " f"node1={to_checksum_address(app1.raiden.address)} " f"node0={to_checksum_address(app0.raiden.address)} " f"block_number0={block_number0} " f"block_number1={block_number1} " f"state_change_id0={saved_state0.state_change_id} " f"state_change_id1={saved_state1.state_change_id}.") raise AssertionError(msg)
def start(self): """ Start the node synchronously. Raises directly if anything went wrong on startup """ assert self.stop_event.ready(), f"Node already started. node:{self!r}" self.stop_event.clear() self.greenlets = list() self.ready_to_process_events = False # set to False because of restarts if self.database_dir is not None: self.db_lock.acquire(timeout=0) assert self.db_lock.is_locked, f"Database not locked. node:{self!r}" # 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"], ) self.maybe_upgrade_db() storage = sqlite.SerializedSQLiteStorage( database_path=self.database_path, serializer=serialize.JSONSerializer()) storage.update_version() storage.log_run() 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, creating 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 last_log_block_hash = self.chain.client.blockhash_from_blocknumber( last_log_block_number) state_change = ActionInitChain( pseudo_random_generator=random.Random(), block_number=last_log_block_number, block_hash=last_log_block_hash, our_address=self.chain.node_address, chain_id=self.chain.network_id, ) self.handle_and_track_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( transaction_hash=constants.EMPTY_HASH, payment_network=payment_network, block_number=last_log_block_number, block_hash=last_log_block_hash, ) self.handle_and_track_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 latest confirmed 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_payment_statuses(chain_state) self._initialize_transactions_queues(chain_state) self._initialize_messages_queues(chain_state) self._initialize_whitelists(chain_state) self._initialize_monitoring_services_queue(chain_state) self._initialize_ready_to_processed_events() if self.config["transport_type"] == "udp": endpoint_registration_greenlet.get( ) # re-raise if exception occurred # Start the side-effects: # - React to blockchain events # - React to incoming messages # - Send pending transactions # - Send pending message self.alarm.link_exception(self.on_error) self.transport.link_exception(self.on_error) self._start_transport(chain_state) self._start_alarm_task() log.debug("Raiden Service started", node=pex(self.address)) super().start()
def get_block_number(self) -> BlockNumber: return views.block_number(self.wal.state_manager.current_state)
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) with self.dispatch_events_lock: 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( raiden_service=self, message_handler=self.message_handler, prev_auth_data=chain_state.last_transport_authdata, ) # 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 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
def get_block_number(self) -> BlockNumber: assert self.wal, f"WAL object not yet initialized. node:{self!r}" return views.block_number(self.wal.state_manager.current_state)
def get_block_number(self): return views.block_number(self.wal.state_manager.current_state)
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()
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()