def get_mix_results(web3: Any, mixer_instance: Any, start_block: int, end_block: int, batch_size: Optional[int] = None) -> Iterator[MixResult]: """ Iterator for all events generated by 'mix' executions, over some block range (inclusive of `end_block`). Batch eth RPC calls to avoid too many calls, and holding huge lists of events in memory. """ contract_address = mixer_instance.address event_abi = find_matching_event_abi(mixer_instance.abi, event_name="LogMix") batch_size = batch_size or SYNC_BLOCKS_PER_BATCH while start_block <= end_block: # Filters are *inclusive* wrt "toBlock", hence the -1 here, and + 1 to # set start_block before iterating. to_block = min(start_block + batch_size - 1, end_block) filter_params = { 'fromBlock': start_block, 'toBlock': to_block, 'address': contract_address, } logs = web3.eth.getLogs(filter_params) for log in logs: event_data = get_event_data(event_abi, log) yield _event_args_to_mix_result(event_data.args) start_block = to_block + 1
def log_entry_formatters(contract_abi, filter_names): formatters = {} for filter_name in filter_names: formatter = functools.partial( get_event_data, find_matching_event_abi(contract_abi, filter_name)) formatters[filter_name] = formatter return formatters
def get_event_abi(self, contract_name: str, event_name: str) -> Dict: """ Returns the ABI for a given event. """ # Import locally to avoid web3 dependency during installation via `compile_contracts` from web3.utils.contracts import find_matching_event_abi assert self.contracts, 'ContractManager should have contracts compiled' contract_abi = self.get_contract_abi(contract_name) return find_matching_event_abi(contract_abi, event_name)
def get_event_abi(self, contract_name: str, event_name: str) -> Dict: """ Returns the ABI for a given event. """ # Import locally to avoid web3 dependency during installation via `compile_contracts` from web3.utils.contracts import find_matching_event_abi if not self.contracts: self.compile_contracts() contract_abi = self.get_contract_abi(contract_name) return find_matching_event_abi(contract_abi, event_name)
def __init__(self, ethereum_node_uri, contract_abi, contract_address, logger): self.logger = logger self.abi = contract_abi self.contract_address = Web3.toChecksumAddress(contract_address) self.web3 = Web3(HTTPProvider(ethereum_node_uri)) self.contract = self.web3.eth.contract(abi=self.abi, address=self.contract_address) self.event_abi = find_matching_event_abi(self.abi, event_name="Transfer") self.event_topic = event_abi_to_log_topic(self.event_abi)
def tokenadded_filter(self, from_block: Optional[BlockNumber] = None ) -> StatelessFilter: event_abi = find_matching_event_abi( abi=self.metadata.abi, event_name=EVENT_TOKEN_NETWORK_CREATED) topics: List[Optional[str]] = [ encode_hex(event_abi_to_log_topic(event_abi)) ] if from_block is None: from_block = self.metadata.filters_start_at registry_address_bin = self.proxy.contract_address return self.rpc_client.new_filter( contract_address=registry_address_bin, topics=topics, from_block=from_block)
async def get_new_entries_from_logs( self, event_name: str, block_hashes: List[HexBytes]) -> List[AttributeDict]: event_abi: Dict[str, any] = self._event_abi_map.get(event_name, None) if event_abi is None: event_abi = find_matching_event_abi(self._contract_abi, event_name=event_name) self._event_abi_map[event_name] = event_abi _, event_filter_params = construct_event_filter_params( event_abi, contract_address=self._address) tasks = [] for block_hash in block_hashes: event_filter_params["blockHash"] = block_hash.hex() tasks.append(self._get_logs(event_filter_params)) raw_logs = await asyncio.gather(*tasks, return_exceptions=True) logs: List[any] = list(cytoolz.concat(raw_logs)) new_entries = [] for log in logs: event_data: AttributeDict = get_event_data(event_abi, log) event_data_block_number: int = event_data["blockNumber"] event_data_tx_hash: HexBytes = event_data["transactionHash"] if event_data_tx_hash not in self._event_cache: if event_data_block_number not in self._block_events: self._block_events[event_data_block_number] = [ event_data_tx_hash ] else: self._block_events[event_data_block_number].append( event_data_tx_hash) self._event_cache.add(event_data_tx_hash) new_entries.append(event_data) else: self.logger().debug( f"Duplicate event transaction hash found - '{event_data_tx_hash.hex()}'." ) while len(self._block_events) > self._block_events_window_size: tx_hashes: List[HexBytes] = self._block_events.popitem( last=False)[1] for tx_hash in tx_hashes: self._event_cache.remove(tx_hash) return new_entries
def get_event_logs(web3: Any, instance: Any, event_name: str, start_block: int, end_block: int, batch_size: Optional[int]) -> Iterator[Any]: """ Query the attached node for all events emitted by the given contract instance, with the given name. Yields an iterator of event-specific objects to be decoded by the caller. """ contract_address = instance.address event_abi = find_matching_event_abi(instance.abi, event_name=event_name) batch_size = batch_size or SYNC_BLOCKS_PER_BATCH while start_block <= end_block: # Filters are *inclusive* wrt "toBlock", hence the -1 here, and +1 to # set start_block before iterating. to_block = min(start_block + batch_size - 1, end_block) filter_params = { 'fromBlock': start_block, 'toBlock': to_block, 'address': contract_address, } logs = web3.eth.getLogs(filter_params) for log in logs: yield get_event_data(event_abi, log) start_block = to_block + 1
def _find_matching_event_abi(cls, event_name=None, argument_names=None): return find_matching_event_abi(abi=cls.abi, event_name=event_name, argument_names=argument_names)
def _get_event_abi(cls): return find_matching_event_abi(cls.contract_abi, event_name=cls.event_name)
def get_event_abi(self, contract_name: str, event_name: str) -> Dict: """ Returns the ABI for a given event. """ contract_abi = self.get_contract_abi(contract_name) return find_matching_event_abi(contract_abi, event_name)
def _get_event_abi(cls): return find_matching_event_abi( cls.contract_abi, event_name=cls.event_name)
def _find_matching_event_abi(cls, event_name=None, argument_names=None): return find_matching_event_abi( abi=cls.abi, event_name=event_name, argument_names=argument_names)
def get_event_abi(self, contract_name: str, event_name: str) -> Dict: """ Returns the ABI for a given event. """ if not self._contracts: self._compile_all_contracts() contract_abi = self.get_contract_abi(contract_name) return find_matching_event_abi(contract_abi, event_name)