def get_contract_events( chain: BlockChainService, abi: Dict, contract_address: Address, topics: List[str], from_block: BlockSpecification, to_block: BlockSpecification, ) -> List[Dict]: """ Query the blockchain for all events of the smart contract at `contract_address` that match the filters `topics`, `from_block`, and `to_block`. """ verify_block_number(from_block, 'from_block') verify_block_number(to_block, 'to_block') events = chain.client.get_filter_events( contract_address, topics=topics, from_block=from_block, to_block=to_block, ) result = [] for event in events: decoded_event = dict(decode_event(abi, event)) if event.get('blockNumber'): decoded_event['block_number'] = event['blockNumber'] result.append(decoded_event) return result
def __init__( self, token_network: TokenNetwork, channel_identifier: typing.ChannelID, ): filter_args = get_filter_args_for_specific_event_from_channel( token_network_address=token_network.address, channel_identifier=channel_identifier, event_name=EVENT_CHANNEL_OPENED, ) events = token_network.proxy.contract.web3.eth.getLogs(filter_args) if not len(events) > 0: raise ValueError('Channel is non-existing.') event = decode_event(CONTRACT_MANAGER.get_contract_abi(CONTRACT_TOKEN_NETWORK), events[-1]) participant1 = decode_hex(event['args']['participant1']) participant2 = decode_hex(event['args']['participant2']) if token_network.node_address not in (participant1, participant2): raise ValueError('One participant must be the node address') if token_network.node_address == participant2: participant1, participant2 = participant2, participant1 self.channel_identifier = channel_identifier self.channel_operations_lock = RLock() self.participant1 = participant1 self.participant2 = participant2 self.token_network = token_network
def poll_blockchain_events(self, block_number: int = None): # When we test with geth if the contracts have already been deployed # before the filter creation we need to use `get_all_entries` to make # sure we get all the events. With tester this is not required. for event_listener in self.event_listeners: if isinstance(event_listener.filter, StatelessFilter): events = event_listener.filter.get_new_entries(block_number) elif event_listener.first_run is True: events = event_listener.filter.get_all_entries() index = self.event_listeners.index(event_listener) self.event_listeners[index] = event_listener._replace(first_run=False) else: events = event_listener.filter.get_new_entries() for log_event in events: decoded_event = dict(decode_event( event_listener.abi, log_event, )) if decoded_event is not None: decoded_event['block_number'] = log_event.get('blockNumber', 0) event = Event( to_canonical_address(log_event['address']), decoded_event, ) yield decode_event_to_internal(event)
def poll_blockchain_events(self, block_number: int = None): # When we test with geth if the contracts have already been deployed # before the filter creation we need to use `get_all_entries` to make # sure we get all the events. With tester this is not required. for event_listener in self.event_listeners: if isinstance(event_listener.filter, StatelessFilter): events = event_listener.filter.get_new_entries(block_number) elif event_listener.first_run is True: events = event_listener.filter.get_all_entries() index = self.event_listeners.index(event_listener) self.event_listeners[index] = event_listener._replace( first_run=False) else: events = event_listener.filter.get_new_entries() for log_event in events: decoded_event = dict( decode_event( event_listener.abi, log_event, )) if decoded_event is not None: decoded_event['block_number'] = log_event.get( 'blockNumber', 0) event = Event( to_canonical_address(log_event['address']), decoded_event, ) yield decode_event_to_internal(event)
def __init__( self, token_network: TokenNetwork, channel_identifier: typing.ChannelID, ): filter_args = get_filter_args_for_specific_event_from_channel( token_network_address=token_network.address, channel_identifier=channel_identifier, event_name=EVENT_CHANNEL_OPENED, ) events = token_network.proxy.contract.web3.eth.getLogs(filter_args) if not len(events) > 0: raise ValueError('Channel is non-existing.') event = decode_event( CONTRACT_MANAGER.get_contract_abi(CONTRACT_TOKEN_NETWORK), events[-1]) participant1 = decode_hex(event['args']['participant1']) participant2 = decode_hex(event['args']['participant2']) if token_network.node_address not in (participant1, participant2): raise ValueError('One participant must be the node address') if token_network.node_address == participant2: participant1, participant2 = participant2, participant1 self.channel_identifier = channel_identifier self.channel_operations_lock = RLock() self.participant1 = participant1 self.participant2 = participant2 self.token_network = token_network
def decode_event_to_internal(abi, log_event): """ Enforce the binary for internal usage. """ # Note: All addresses inside the event_data must be decoded. decoded_event = decode_event(abi, log_event) if not decoded_event: raise UnknownEventType() # copy the attribute dict because that data structure is immutable data = dict(decoded_event) args = dict(data['args']) data['args'] = args # translate from web3's to raiden's name convention data['block_number'] = log_event.pop('blockNumber') data['transaction_hash'] = log_event.pop('transactionHash') data['block_hash'] = bytes(log_event.pop('blockHash')) assert data['block_number'], 'The event must have the block_number' assert data[ 'transaction_hash'], 'The event must have the transaction hash field' event = data['event'] if event == EVENT_TOKEN_NETWORK_CREATED: args['token_network_address'] = to_canonical_address( args['token_network_address']) args['token_address'] = to_canonical_address(args['token_address']) elif event == ChannelEvent.OPENED: args['participant1'] = to_canonical_address(args['participant1']) args['participant2'] = to_canonical_address(args['participant2']) elif event == ChannelEvent.DEPOSIT: args['participant'] = to_canonical_address(args['participant']) elif event == ChannelEvent.BALANCE_PROOF_UPDATED: args['closing_participant'] = to_canonical_address( args['closing_participant']) elif event == ChannelEvent.CLOSED: args['closing_participant'] = to_canonical_address( args['closing_participant']) elif event == ChannelEvent.UNLOCKED: args['participant'] = to_canonical_address(args['participant']) args['partner'] = to_canonical_address(args['partner']) return Event( originating_contract=to_canonical_address(log_event['address']), event_data=data, )
def __init__( self, token_network: TokenNetwork, channel_identifier: ChannelID, contract_manager: ContractManager, ): if channel_identifier <= 0 or channel_identifier > UINT256_MAX: raise ValueError( f"channel_identifier {channel_identifier} is not a uint256") # FIXME: Issue #3958 from_block = GENESIS_BLOCK_NUMBER # For this check it is perfectly fine to use a `latest` block number. # If the channel happened to be closed, even if the chanel is already # closed/settled. to_block = "latest" filter_args = get_filter_args_for_specific_event_from_channel( token_network_address=token_network.address, channel_identifier=channel_identifier, event_name=ChannelEvent.OPENED, contract_manager=contract_manager, from_block=from_block, to_block=to_block, ) events = token_network.proxy.contract.web3.eth.getLogs(filter_args) if not len(events) > 0: raise ValueError("Channel is non-existing.") event = decode_event( contract_manager.get_contract_abi(CONTRACT_TOKEN_NETWORK), events[-1]) participant1 = Address(decode_hex(event["args"]["participant1"])) participant2 = Address(decode_hex(event["args"]["participant2"])) if token_network.node_address not in (participant1, participant2): raise ValueError("One participant must be the node address") if token_network.node_address == participant2: participant1, participant2 = participant2, participant1 self.channel_identifier = channel_identifier self.participant1 = participant1 self.participant2 = participant2 self.token_network = token_network self.client = token_network.client self.contract_manager = contract_manager
def settle_timeout(self) -> int: """ Returns the channels settle_timeout. """ # There is no way to get the settle timeout after the channel has been closed as # we're saving gas. Therefore get the ChannelOpened event and get the timeout there. filter_args = get_filter_args_for_specific_event_from_channel( token_network_address=self.token_network.address, channel_identifier=self.channel_identifier, event_name=EVENT_CHANNEL_OPENED, ) events = self.token_network.proxy.contract.web3.eth.getLogs(filter_args) assert len(events) > 0, 'No matching ChannelOpen event found.' # we want the latest event here, there might have been multiple channels event = decode_event(CONTRACT_MANAGER.get_contract_abi(CONTRACT_TOKEN_NETWORK), events[-1]) return event['args']['settle_timeout']
def settle_timeout(self) -> int: """ Returns the channels settle_timeout. """ # There is no way to get the settle timeout after the channel has been closed as # we're saving gas. Therefore get the ChannelOpened event and get the timeout there. filter_args = get_filter_args_for_specific_event_from_channel( token_network_address=self.token_network.address, channel_identifier=self.channel_identifier, event_name=ChannelEvent.OPENED, ) events = self.token_network.proxy.contract.web3.eth.getLogs(filter_args) assert len(events) > 0, 'No matching ChannelOpen event found.' # we want the latest event here, there might have been multiple channels event = decode_event(CONTRACT_MANAGER.get_contract_abi(CONTRACT_TOKEN_NETWORK), events[-1]) return event['args']['settle_timeout']
def poll_blockchain_events(self, block_number: int): """ Poll for new blockchain events up to `block_number`. """ for event_listener in self.event_listeners: assert isinstance(event_listener.filter, StatelessFilter) for log_event in event_listener.filter.get_new_entries(block_number): decoded_event = dict(decode_event( event_listener.abi, log_event, )) if decoded_event: decoded_event['block_number'] = log_event.get('blockNumber', 0) event = Event( to_canonical_address(log_event['address']), decoded_event, ) yield decode_event_to_internal(event)
def __init__( self, token_network: TokenNetwork, channel_identifier: ChannelID, contract_manager: ContractManager, ): self.contract_manager = contract_manager if channel_identifier < 0 or channel_identifier > UINT256_MAX: raise ValueError('channel_identifier {} is not a uint256'.format( channel_identifier)) filter_args = get_filter_args_for_specific_event_from_channel( token_network_address=token_network.address, channel_identifier=channel_identifier, event_name=ChannelEvent.OPENED, contract_manager=self.contract_manager, ) events = token_network.proxy.contract.web3.eth.getLogs(filter_args) if not len(events) > 0: raise ValueError('Channel is non-existing.') event = decode_event( self.contract_manager.get_contract_abi(CONTRACT_TOKEN_NETWORK), events[-1], ) participant1 = Address(decode_hex(event['args']['participant1'])) participant2 = Address(decode_hex(event['args']['participant2'])) if token_network.node_address not in (participant1, participant2): raise ValueError('One participant must be the node address') if token_network.node_address == participant2: participant1, participant2 = participant2, participant1 self.channel_identifier = channel_identifier self.participant1 = participant1 self.participant2 = participant2 self.token_network = token_network self.client = self.token_network.client
def close_block_number(self) -> typing.Optional[int]: """ Returns the channel's closed block number. """ # The closed block number is not in the smart contract storage to save # gas. Therefore get the ChannelClosed event is needed here. filter_args = get_filter_args_for_specific_event_from_channel( token_network_address=self.token_network.address, channel_identifier=self.channel_identifier, event_name=ChannelEvent.CLOSED, ) events = self.token_network.proxy.contract.web3.eth.getLogs( filter_args) if not events: return None assert len(events) == 1 event = decode_event( CONTRACT_MANAGER.get_contract_abi(CONTRACT_TOKEN_NETWORK), events[0]) return event['blockNumber']
def close_block_number(self) -> Optional[int]: """ Returns the channel's closed block number. """ # The closed block number is not in the smart contract storage to save # gas. Therefore get the ChannelClosed event is needed here. filter_args = get_filter_args_for_specific_event_from_channel( token_network_address=self.token_network.address, channel_identifier=self.channel_identifier, event_name=ChannelEvent.CLOSED, contract_manager=self.contract_manager, ) events = self.token_network.proxy.contract.web3.eth.getLogs(filter_args) if not events: return None assert len(events) == 1 event = decode_event( self.contract_manager.get_contract_abi(CONTRACT_TOKEN_NETWORK), events[0], ) return event['blockNumber']
def __init__( self, token_network: TokenNetwork, channel_identifier: ChannelID, contract_manager: ContractManager, ): self.contract_manager = contract_manager if channel_identifier < 0 or channel_identifier > UINT256_MAX: raise ValueError('channel_identifier {} is not a uint256'.format(channel_identifier)) filter_args = get_filter_args_for_specific_event_from_channel( token_network_address=token_network.address, channel_identifier=channel_identifier, event_name=ChannelEvent.OPENED, contract_manager=self.contract_manager, ) events = token_network.proxy.contract.web3.eth.getLogs(filter_args) if not len(events) > 0: raise ValueError('Channel is non-existing.') event = decode_event( self.contract_manager.get_contract_abi(CONTRACT_TOKEN_NETWORK), events[-1], ) participant1 = decode_hex(event['args']['participant1']) participant2 = decode_hex(event['args']['participant2']) if token_network.node_address not in (participant1, participant2): raise ValueError('One participant must be the node address') if token_network.node_address == participant2: participant1, participant2 = participant2, participant1 self.channel_identifier = channel_identifier self.participant1 = participant1 self.participant2 = participant2 self.token_network = token_network
def poll_blockchain_events(self): # When we test with geth if the contracts have already been deployed # before the filter creation we need to use `get_all_entries` to make # sure we get all the events. With tester this is not required. if self.first_run: query_fn = 'get_all_entries' self.first_run = False else: query_fn = 'get_new_entries' for event_listener in self.event_listeners: for log_event in getattr(event_listener.filter, query_fn)(): decoded_event = dict(decode_event( event_listener.abi, log_event, )) if decoded_event is not None: decoded_event['block_number'] = log_event.get('blockNumber', 0) event = Event( to_canonical_address(log_event['address']), decoded_event, ) yield decode_event_to_internal(event)
def decode_event(self, log: Dict): return decode_event(self.contract.abi, log)
def test_blockchain( web3, blockchain_rpc_ports, private_keys, ): # pylint: disable=too-many-locals addresses = [ privatekey_to_address(priv) for priv in private_keys ] privatekey = private_keys[0] address = privatekey_to_address(privatekey) total_token = 100 host = '127.0.0.1' jsonrpc_client = JSONRPCClient( host, blockchain_rpc_ports[0], privatekey, web3=web3, ) humantoken_path = get_contract_path('HumanStandardToken.sol') humantoken_contracts = compile_files_cwd([humantoken_path]) token_proxy = jsonrpc_client.deploy_solidity_contract( 'HumanStandardToken', humantoken_contracts, list(), (total_token, 'raiden', 2, 'Rd'), contract_path=humantoken_path, ) token_proxy = Token(jsonrpc_client, to_canonical_address(token_proxy.contract.address)) registry_path = get_contract_path('Registry.sol') registry_contracts = compile_files_cwd([registry_path]) registry_proxy = jsonrpc_client.deploy_solidity_contract( 'Registry', registry_contracts, list(), tuple(), contract_path=registry_path, ) registry_proxy = Registry( jsonrpc_client, to_canonical_address(registry_proxy.contract.address), ) log_list = jsonrpc_client.web3.eth.getLogs( { 'fromBlock': 0, 'toBlock': 'latest', 'topics': [], }, ) assert not log_list assert token_proxy.balance_of(address) == total_token manager_address = registry_proxy.add_token( to_canonical_address(token_proxy.proxy.contract.address), ) assert is_address(manager_address) assert len(registry_proxy.token_addresses()) == 1 log_list = jsonrpc_client.web3.eth.getLogs( { 'fromBlock': 0, 'toBlock': 'latest', 'topics': [], }, ) assert len(log_list) == 1 channel_manager_address_encoded = registry_proxy.manager_address_by_token( token_proxy.proxy.contract.address, ) channel_manager_address = to_canonical_address(channel_manager_address_encoded) log = log_list[0] event = decode_event(CONTRACT_MANAGER.get_contract_abi(CONTRACT_REGISTRY), log) event_args = event['args'] assert channel_manager_address == to_canonical_address(event_args['channel_manager_address']) assert is_same_address(token_proxy.proxy.contract.address, event_args['token_address']) channel_manager_proxy = jsonrpc_client.new_contract_proxy( CONTRACT_MANAGER.get_contract_abi(CONTRACT_CHANNEL_MANAGER), channel_manager_address, ) channel_manager_proxy = ChannelManager( jsonrpc_client, to_canonical_address(channel_manager_proxy.contract.address), ) channel_address = channel_manager_proxy.new_netting_channel( addresses[1], 10, ) assert is_address(channel_address) log_list = jsonrpc_client.web3.eth.getLogs( { 'fromBlock': 0, 'toBlock': 'latest', 'topics': [], }, ) assert len(log_list) == 2