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()
Пример #3
0
    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