def get_balance(self, addr: str) -> Union[str, None]: """ Get balance of an address. Args: addr: Requested address. Returns: Current balance of an address. """ raw_address = db_get_wrapper(self.db, b'address-' + addr.encode()) if raw_address is None: return None address = coder.decode_address(raw_address) return address['balance']
def _update_db_balances(self, addr_balances: Dict) -> None: """ Updates balances of Ethereum addresses in the LevelDB database in batches. Args: addr_balances: Dictionary containing 'address: balance' entries. """ address_objects = {} for address in addr_balances: raw_addr = db_get_wrapper(self.db, b'address-' + str(address).encode()) if raw_addr is None: continue address_objects[address] = coder.decode_address(raw_addr) address_objects[address]['balance'] = addr_balances[address] self.db_lock.acquire() wb = rocksdb.WriteBatch() for address in address_objects: address_value = coder.encode_address(address_objects[address]) wb.put(b'address-' + str(address).encode(), address_value) self.db.write(wb) self.db_lock.release()
def fill_addresses(self, addresses: Dict, transactions: Dict, tokens: Dict, token_txs: List) -> Tuple[Dict, Dict]: """ Fill addresses with transaction information. Args: addresses: Currently processed addresses. transactions: Currently processed transactions. tokens: Currently processed tokens. token_txs: Currently processed token transactions. Returns: Addresses with new information. """ LOG.info('Filling addresses.') updated_tokens, filtered_token_txs = self.expand_tokens( tokens, token_txs) addresses, updated_tokens = self.fill_addresses_tokens( addresses, updated_tokens, filtered_token_txs) addresses_encode = {} addresses_write_dict = {} for addr_hash, addr_dict in addresses.items(): existing_data = db_get_wrapper(self.db, b'address-' + addr_hash.encode()) # Address not yet in records if existing_data is not None: existing_address = coder.decode_address(existing_data) last_input_tx_index = int(existing_address['inputTxIndex']) last_output_tx_index = int(existing_address['outputTxIndex']) last_input_token_tx_index = int( existing_address['inputTokenTxIndex']) last_output_token_tx_index = int( existing_address['outputTokenTxIndex']) last_input_int_tx_index = int( existing_address['inputIntTxIndex']) last_output_int_tx_index = int( existing_address['outputIntTxIndex']) last_mined_block_index = int(existing_address['minedIndex']) else: last_input_tx_index = 0 last_output_tx_index = 0 last_input_token_tx_index = 0 last_output_token_tx_index = 0 last_input_int_tx_index = 0 last_output_int_tx_index = 0 last_mined_block_index = 0 address_encode = {} if existing_data is not None: address_encode['tokenContract'] = existing_address[ 'tokenContract'] if addr_hash in updated_tokens: updated_tokens[addr_hash]['type'] = existing_address[ 'tokenContract'] else: if 'tokenContract' in addr_dict: address_encode['tokenContract'] = addr_dict[ 'tokenContract'] if addr_hash in updated_tokens: updated_tokens[addr_hash]['type'] = addr_dict[ 'tokenContract'] else: address_encode['tokenContract'] = 'False' address_encode['balance'] = 'null' if existing_data is not None: address_encode['code'] = existing_address['code'] else: address_encode['code'] = addr_dict['code'] for input_tx in addr_dict['newInputTxs']: last_input_tx_index += 1 addresses_write_dict[addr_hash + '-i-' + str(last_input_tx_index)] = ( str(input_tx[0]) + '-' + str(input_tx[1]) + '-' + str(input_tx[2])) for output_tx in addr_dict['newOutputTxs']: last_output_tx_index += 1 addresses_write_dict[addr_hash + '-o-' + str(last_output_tx_index)] = ( str(output_tx[0]) + '-' + str(output_tx[1]) + '-' + str(output_tx[2])) for mined_hash in addr_dict['mined']: last_mined_block_index += 1 addresses_write_dict[addr_hash + '-b-' + str(last_mined_block_index)] = mined_hash address_encode['inputTxIndex'] = last_input_tx_index address_encode['outputTxIndex'] = last_output_tx_index address_encode['inputTokenTxIndex'] = last_input_token_tx_index address_encode['outputTokenTxIndex'] = last_output_token_tx_index address_encode['inputIntTxIndex'] = last_input_int_tx_index address_encode['outputIntTxIndex'] = last_output_int_tx_index address_encode['minedIndex'] = last_mined_block_index addresses_encode[addr_hash] = address_encode # Also add token information to the addresses. addresses_encode, updated_tokens, addresses_write_dict = self.fill_addrs_token_txs( addresses, addresses_encode, updated_tokens, addresses_write_dict) # Also add internal transactions to addresses addresses_encode, addresses_write_dict = self.fill_addrs_int_txs( addresses, addresses_encode, addresses_write_dict) return (addresses_encode, addresses_write_dict, updated_tokens, filtered_token_txs)
def get_address(self, addr: str, time_from: int, time_to: int, val_from: int, val_to: int, no_tx_list: int) -> Union[List[Dict[str, Any]], None]: """ Get information of an address, with the possibility of filtering/limiting transactions. Args: addr: Ethereum address. time_from: Beginning datetime to take transactions from. time_to: Ending datetime to take transactions from. val_from: Minimum transferred currency of the transactions. val_to: Maximum transferred currency of transactions. no_tx_list: Maximum transactions to return. Returns: Address information along with its transactions. """ raw_address = db_get_wrapper(self.db, b'address-' + addr.encode()) if raw_address is None: return None address = coder.decode_address(raw_address) if address['code'] != '0x': raw_code = db_get_wrapper( self.db, b'address-contract-' + address['code'].encode()) address['code'] = raw_code.decode() input_transactions, output_transactions = ( self.get_transactions_of_address(addr, time_from, time_to, val_from, val_to, no_tx_list, True)) address.pop('inputTxIndex', None) address.pop('outputTxIndex', None) address['inputTransactions'] = input_transactions address['outputTransactions'] = output_transactions input_int_transactions, output_int_transactions = ( self.get_internal_txs_of_address(addr, time_from, time_to, val_from, val_to, no_tx_list, True)) address.pop('inputIntTxIndex', None) address.pop('outputIntTxIndex', None) address['inputInternalTransactions'] = input_int_transactions address['outputInternalTransactions'] = output_int_transactions mined_hashes = [] # type: List[bytes] if address['minedIndex'] > 0: prefix = 'associated-data-' + addr + '-b-' mined_hashes = db_iter_wrapper(self.db, prefix) address.pop('minedIndex', None) address['mined'] = list(map(lambda x: x.decode(), mined_hashes)) input_token_txs, output_token_txs = (self.get_token_txs_of_address( addr, time_from, time_to, no_tx_list, True)) address.pop('inputTokenTxIndex', None) address.pop('outputTokenTxIndex', None) address['inputTokenTransactions'] = input_token_txs address['outputTokenTransactions'] = output_token_txs return address
def get_token_txs_of_address(self, addr: str, time_from: int, time_to: int, no_tx_list: int, internal=False) -> Any: """ Get token txs of specified address, with filtering by time and transferred capital. Args: addr: Ethereum address. time_from: Beginning datetime to take transactions from. time_to: Ending datetime to take transactions from. no_tx_list: Maximum transactions to return. internal: Whether this method was called internally. Returns: List of token transactions of an address. """ raw_address = db_get_wrapper(self.db, b'address-' + addr.encode()) if raw_address is None: return None address = coder.decode_address(raw_address) input_token_txs = [] output_token_txs = [] input_token_tx_indexes = [] # type: List[bytes] output_token_tx_indexes = [] # type: List[bytes] if address['inputTokenTxIndex'] > 0: prefix = 'associated-data-' + addr + '-ti-' input_token_tx_indexes = db_iter_wrapper(self.db, prefix) if address['outputTokenTxIndex'] > 0: prefix = 'associated-data-' + addr + '-to-' output_token_tx_indexes = db_iter_wrapper(self.db, prefix) found_txs = 0 for token_tx_index in input_token_tx_indexes: if found_txs >= no_tx_list: break tx_decoded = token_tx_index.decode() tx_index, timestamp = tx_decoded.split('-') if (time_from <= int(timestamp) and time_to >= int(timestamp)): raw_tx = db_get_wrapper(self.db, b'token-tx-' + tx_index.encode()) token_tx = coder.decode_token_tx(raw_tx) input_token_txs.append(token_tx) found_txs += 1 for token_tx_index in output_token_tx_indexes: if found_txs >= no_tx_list: break tx_decoded = token_tx_index.decode() tx_index, timestamp = tx_decoded.split('-') if (time_from <= int(timestamp) and time_to >= int(timestamp)): raw_tx = db_get_wrapper(self.db, b'token-tx-' + tx_index.encode()) token_tx = coder.decode_token_tx(raw_tx) output_token_txs.append(token_tx) found_txs += 1 if internal: return (input_token_txs, output_token_txs) else: return input_token_txs + output_token_txs
def get_transactions_of_address(self, addr: str, time_from: int, time_to: int, val_from: int, val_to: int, no_tx_list: int, internal=False) -> Any: """ Get transactions of specified address, with filtering by time and transferred capital. Args: addr: Ethereum address. time_from: Beginning datetime to take transactions from. time_to: Ending datetime to take transactions from. val_from: Minimum transferred currency of the transactions. val_to: Maximum transferred currency of transactions. no_tx_list: Maximum transactions to return. internal: Whether this method was called internally. Returns: List of address transactions. """ raw_address = db_get_wrapper(self.db, b'address-' + addr.encode()) if raw_address is None: return None address = coder.decode_address(raw_address) input_tx_hashes = [] # type: List[bytes] output_tx_hashes = [] # type: List[bytes] if address['inputTxIndex'] > 0: prefix = 'associated-data-' + addr + '-i-' input_tx_hashes = db_iter_wrapper(self.db, prefix) if address['outputTxIndex'] > 0: prefix = 'associated-data-' + addr + '-o-' output_tx_hashes = db_iter_wrapper(self.db, prefix) found_txs = 0 input_transactions = [] for tx_data in input_tx_hashes: if found_txs >= no_tx_list: break tx_decoded = tx_data.decode() tx_hash, value, timestamp = tx_decoded.split('-') if (time_from <= int(timestamp) and time_to >= int(timestamp) and val_from <= int(value) and val_to >= int(value)): transaction = self.get_transaction_by_hash(tx_hash) transaction.pop('internalTransactions', None) # type: ignore input_transactions.append(transaction) found_txs += 1 output_transactions = [] for tx_data in output_tx_hashes: if found_txs >= no_tx_list: break tx_decoded = tx_data.decode() tx_hash, value, timestamp = tx_decoded.split('-') if (time_from <= int(timestamp) and time_to >= int(timestamp) and val_from <= int(value) and val_to >= int(value)): transaction = self.get_transaction_by_hash(tx_hash) transaction.pop('internalTransactions', None) # type: ignore output_transactions.append(transaction) found_txs += 1 if internal: return (input_transactions, output_transactions) else: return input_transactions + output_transactions