def _callback_new_block(self, latest_block: Dict): """Called once a new block is detected by the alarm task. Note: This should be called only once per block, otherwise there will be duplicated `Block` state changes in the log. Therefore this method should be called only once a new block is mined with the corresponding block data from the AlarmTask. """ # User facing APIs, which have on-chain side-effects, force polled the # blockchain to update the node's state. This force poll is used to # provide a consistent view to the user, e.g. a channel open call waits # for the transaction to be mined and force polled the event to update # the node's state. This pattern introduced a race with the alarm task # and the task which served the user request, because the events are # returned only once per filter. The lock below is to protect against # these races (introduced by the commit # 3686b3275ff7c0b669a6d5e2b34109c3bdf1921d) with self.event_poll_lock: latest_block_number = latest_block["number"] # Handle testing with private chains. The block number can be # smaller than confirmation_blocks confirmed_block_number = max( GENESIS_BLOCK_NUMBER, latest_block_number - self.config["blockchain"]["confirmation_blocks"], ) confirmed_block = self.chain.client.web3.eth.getBlock( confirmed_block_number) # These state changes will be procesed with a block_number which is # /larger/ than the ChainState's block_number. for event in self.blockchain_events.poll_blockchain_events( confirmed_block_number): on_blockchain_event(self, event) # On restart the Raiden node will re-create the filters with the # ethereum node. These filters will have the from_block set to the # value of the latest Block state change. To avoid missing events # the Block state change is dispatched only after all of the events # have been processed. # # This means on some corner cases a few events may be applied # twice, this will happen if the node crashed and some events have # been processed but the Block state change has not been # dispatched. state_change = Block( block_number=confirmed_block_number, gas_limit=confirmed_block["gasLimit"], block_hash=BlockHash(bytes(confirmed_block["hash"])), ) # Note: It's important to /not/ block here, because this function # can be called from the alarm task greenlet, which should not # starve. self.handle_and_track_state_change(state_change)
def install_and_query_all_blockchain_filters( self, token_network_registry_address, secret_registry_address, from_block=0, ): token_network_registry = self.chain.token_network_registry( token_network_registry_address) secret_registry = self.chain.secret_registry(secret_registry_address) channels = views.list_all_channelstate(views.state_from_raiden(self), ) token_networks = views.get_token_network_identifiers( views.state_from_raiden(self), token_network_registry_address, ) # Install the filters and then poll them and dispatch the events to the WAL with self.event_poll_lock: self.blockchain_events.add_token_network_registry_listener( token_network_registry, from_block, ) self.blockchain_events.add_secret_registry_listener( secret_registry, from_block, ) for token_network in token_networks: token_network_proxy = self.chain.token_network(token_network) self.blockchain_events.add_token_network_listener( token_network_proxy, from_block, ) for channel_state in channels: channel_proxy = self.chain.payment_channel( channel_state.token_network_identifier, channel_state.identifier, ) self.blockchain_events.add_payment_channel_listener( channel_proxy, from_block, ) chain_id = self.chain.network_id # We need to query the events at this point in order to obtain an up to # date view of the blockchain right before the node starts its transport # and starts receiving messages. for event in self.blockchain_events.poll_blockchain_events( self.get_block_number(), ): on_blockchain_event( self, event, event.event_data['block_number'], chain_id, )
def install_and_query_payment_network_filters(self, payment_network_id, from_block=0): proxies = get_relevant_proxies( self.chain, self.address, payment_network_id, ) # Install the filters and then poll them and dispatch the events to the WAL with self.event_poll_lock: self.blockchain_events.add_proxies_listeners(proxies, from_block) for event in self.blockchain_events.poll_blockchain_events(): on_blockchain_event(self, event, event.event_data['block_number'])
def _callback_new_block(self, latest_block: Dict): """Called once a new block is detected by the alarm task. Note: This should be called only once per block, otherwise there will be duplicated `Block` state changes in the log. Therefore this method should be called only once a new block is mined with the corresponding block data from the AlarmTask. """ # User facing APIs, which have on-chain side-effects, force polled the # blockchain to update the node's state. This force poll is used to # provide a consistent view to the user, e.g. a channel open call waits # for the transaction to be mined and force polled the event to update # the node's state. This pattern introduced a race with the alarm task # and the task which served the user request, because the events are # returned only once per filter. The lock below is to protect against # these races (introduced by the commit # 3686b3275ff7c0b669a6d5e2b34109c3bdf1921d) with self.event_poll_lock: latest_block_number = latest_block['number'] confirmation_blocks = self.config['blockchain']['confirmation_blocks'] confirmed_block_number = latest_block_number - confirmation_blocks confirmed_block = self.chain.client.web3.eth.getBlock(confirmed_block_number) # handle testing private chains confirmed_block_number = max(GENESIS_BLOCK_NUMBER, confirmed_block_number) for event in self.blockchain_events.poll_blockchain_events(confirmed_block_number): # These state changes will be procesed with a block_number # which is /larger/ than the ChainState's block_number. on_blockchain_event(self, event) # On restart the Raiden node will re-create the filters with the # ethereum node. These filters will have the from_block set to the # value of the latest Block state change. To avoid missing events # the Block state change is dispatched only after all of the events # have been processed. # # This means on some corner cases a few events may be applied # twice, this will happen if the node crashed and some events have # been processed but the Block state change has not been # dispatched. state_change = Block( block_number=confirmed_block_number, gas_limit=confirmed_block['gasLimit'], block_hash=bytes(confirmed_block['hash']), ) self.handle_state_change(state_change)
def _callback_new_block(self, latest_block): """Called once a new block is detected by the alarm task. Note: This should be called only once per block, otherwise there will be duplicated `Block` state changes in the log. Therefore this method should be called only once a new block is mined with the appropriate block_number argument from the AlarmTask. """ # Raiden relies on blockchain events to update its off-chain state, # therefore some APIs /used/ to forcefully poll for events. # # This was done for APIs which have on-chain side-effects, e.g. # openning a channel, where polling the event is required to update # off-chain state to providing a consistent view to the caller, e.g. # the channel exists after the API call returns. # # That pattern introduced a race, because the events are returned only # once per filter, and this method would be called concurrently by the # API and the AlarmTask. The following lock is necessary, to ensure the # expected side-effects are properly applied (introduced by the commit # 3686b3275ff7c0b669a6d5e2b34109c3bdf1921d) latest_block_number = latest_block['number'] with self.event_poll_lock: for event in self.blockchain_events.poll_blockchain_events( latest_block_number): # These state changes will be procesed with a block_number # which is /larger/ than the ChainState's block_number. on_blockchain_event(self, event) # On restart the Raiden node will re-create the filters with the # ethereum node. These filters will have the from_block set to the # value of the latest Block state change. To avoid missing events # the Block state change is dispatched only after all of the events # have been processed. # # This means on some corner cases a few events may be applied # twice, this will happen if the node crashed and some events have # been processed but the Block state change has not been # dispatched. state_change = Block( block_number=latest_block_number, gas_limit=latest_block['gasLimit'], block_hash=bytes(latest_block['hash']), ) self.handle_state_change(state_change)
def install_and_query_payment_network_filters( self, token_network_registry_address, from_block=0, ): token_network_registry = self.chain.token_network_registry(token_network_registry_address) # Install the filters and then poll them and dispatch the events to the WAL with self.event_poll_lock: self.blockchain_events.add_token_network_registry_listener( token_network_registry, from_block, ) for event in self.blockchain_events.poll_blockchain_events(): on_blockchain_event(self, event, event.event_data['block_number'])
def _callback_new_block(self, latest_block): """Called once a new block is detected by the alarm task. Note: This should be called only once per block, otherwise there will be duplicated `Block` state changes in the log. Therefore this method should be called only once a new block is mined with the corresponding block data from the AlarmTask. """ # User facing APIs, which have on-chain side-effects, force polled the # blockchain to update the node's state. This force poll is used to # provide a consistent view to the user, e.g. a channel open call waits # for the transaction to be mined and force polled the event to update # the node's state. This pattern introduced a race with the alarm task # and the task which served the user request, because the events are # returned only once per filter. The lock below is to protect against # these races (introduced by the commit # 3686b3275ff7c0b669a6d5e2b34109c3bdf1921d) with self.event_poll_lock: latest_block_number = latest_block['number'] for event in self.blockchain_events.poll_blockchain_events( latest_block_number): # These state changes will be procesed with a block_number # which is /larger/ than the ChainState's block_number. on_blockchain_event(self, event) # On restart the Raiden node will re-create the filters with the # ethereum node. These filters will have the from_block set to the # value of the latest Block state change. To avoid missing events # the Block state change is dispatched only after all of the events # have been processed. # # This means on some corner cases a few events may be applied # twice, this will happen if the node crashed and some events have # been processed but the Block state change has not been # dispatched. state_change = Block( block_number=latest_block_number, gas_limit=latest_block['gasLimit'], block_hash=bytes(latest_block['hash']), ) self.handle_state_change(state_change)
def _callback_new_block(self, current_block_number, chain_id): """Called once a new block is detected by the alarm task. Note: This should be called only once per block, otherwise there will be duplicated `Block` state changes in the log. Therefore this method should be called only once a new block is mined with the appropriate block_number argument from the AlarmTask. """ # Raiden relies on blockchain events to update its off-chain state, # therefore some APIs /used/ to forcefully poll for events. # # This was done for APIs which have on-chain side-effects, e.g. # openning a channel, where polling the event is required to update # off-chain state to providing a consistent view to the caller, e.g. # the channel exists after the API call returns. # # That pattern introduced a race, because the events are returned only # once per filter, and this method would be called concurrently by the # API and the AlarmTask. The following lock is necessary, to ensure the # expected side-effects are properly applied (introduced by the commit # 3686b3275ff7c0b669a6d5e2b34109c3bdf1921d) with self.event_poll_lock: for event in self.blockchain_events.poll_blockchain_events(current_block_number): # These state changes will be procesed with a block_number # which is /larger/ than the ChainState's block_number. on_blockchain_event(self, event, current_block_number, chain_id) # On restart the Raiden node will re-create the filters with the # ethereum node. These filters will have the from_block set to the # value of the latest Block state change. To avoid missing events # the Block state change is dispatched only after all of the events # have been processed. # # This means on some corner cases a few events may be applied # twice, this will happen if the node crashed and some events have # been processed but the Block state change has not been # dispatched. state_change = Block(current_block_number) self.handle_state_change(state_change, current_block_number)
def poll_blockchain_events(self, current_block=None): # pylint: disable=unused-argument with self.event_poll_lock: for event in self.blockchain_events.poll_blockchain_events(): on_blockchain_event(self, event)