def get_address(currency, address): db = get_connection() result = db.get_address(currency, address) if not result: raise RuntimeError("Address {} not found in currency {}".format( address, currency)) return Address( address=result.address, first_tx=TxSummary(result.first_tx.height, result.first_tx.timestamp, result.first_tx.tx_hash.hex()), last_tx=TxSummary(result.last_tx.height, result.last_tx.timestamp, result.last_tx.tx_hash.hex()), no_incoming_txs=result.no_incoming_txs, no_outgoing_txs=result.no_outgoing_txs, total_received=make_values(value=result.total_received.value, eur=result.total_received.eur, usd=result.total_received.usd), total_spent=make_values(eur=result.total_spent.eur, usd=result.total_spent.usd, value=result.total_spent.value), in_degree=result.in_degree, out_degree=result.out_degree, balance=convert_value( compute_balance( result.total_received.value, result.total_spent.value, ), get_rates(currency)['rates']))
def get_statistics(): """ Returns summary statistics on all available currencies """ with open('./openapi_server/openapi/openapi.yaml', 'r') as input_file: input = yaml.safe_load(input_file) version = input['info']['version'] title = input['info']['title'] currency_stats = list() db = get_connection() for currency in db.get_supported_currencies(): currency_stats.append(get_currency_statistics(currency, version)) return Stats(currencies=currency_stats, version=StatsVersion(nr=version, hash=None, timestamp=time.strftime( "%Y-%m-%d %H:%M:%S", time.gmtime()), file=version), tools=[ StatsTool(visible_name=title, version=version, id='ait:graphsense', titanium_replayable=False, responsible_for=[]) ], tags_source=StatsTagsSource( visible_name="GraphSense attribution tags", version=version, id="graphsense_tags", report_uuid="graphsense_tags"), notes=[StatsNote(note=note1), StatsNote(note=note2)])
def list_entity_addresses(currency, entity, page=None, pagesize=None): db = get_connection() addresses, paging_state = \ db.list_entity_addresses(currency, entity, page, pagesize) rates = get_rates(currency)['rates'] addresses = [ Address(address=row['address'], first_tx=TxSummary(row['first_tx'].height, row['first_tx'].timestamp, row['first_tx'].tx_hash.hex()), last_tx=TxSummary(row['last_tx'].height, row['last_tx'].timestamp, row['last_tx'].tx_hash.hex()), no_incoming_txs=row['no_incoming_txs'], no_outgoing_txs=row['no_outgoing_txs'], total_received=make_values(value=row['total_received'].value, eur=row['total_received'].eur, usd=row['total_received'].usd), total_spent=make_values(eur=row['total_spent'].eur, usd=row['total_spent'].usd, value=row['total_spent'].value), in_degree=row['in_degree'], out_degree=row['out_degree'], balance=convert_value( compute_balance( row['total_received'].value, row['total_spent'].value, ), rates)) for row in addresses ] return EntityAddresses(next_page=paging_state, addresses=addresses)
def get_entity(currency, entity): db = get_connection() result = db.get_entity(currency, entity) if result is None: raise RuntimeError("Entity {} not found".format(entity)) return Entity(entity=result.cluster, first_tx=TxSummary(result.first_tx.height, result.first_tx.timestamp, result.first_tx.tx_hash.hex()), last_tx=TxSummary(result.last_tx.height, result.last_tx.timestamp, result.last_tx.tx_hash.hex()), no_addresses=result.no_addresses, no_incoming_txs=result.no_incoming_txs, no_outgoing_txs=result.no_outgoing_txs, total_received=make_values(value=result.total_received.value, eur=result.total_received.eur, usd=result.total_received.usd), total_spent=make_values(eur=result.total_spent.eur, usd=result.total_spent.usd, value=result.total_spent.value), in_degree=result.in_degree, out_degree=result.out_degree, balance=convert_value( compute_balance( result.total_received.value, result.total_spent.value, ), get_rates(currency)['rates']))
def list_address_neighbors(currency, address, direction, page=None, pagesize=None): is_outgoing = "out" in direction db = get_connection() results, paging_state = db.list_address_relations( currency, address, is_outgoing, page, pagesize) dst = 'dst' if is_outgoing else 'src' rates = get_rates(currency)['rates'] relations = [] if results is None: return Neighbors() for row in results: balance = compute_balance(row[dst+'_properties'].total_received.value, row[dst+'_properties'].total_spent.value) relations.append(Neighbor( id=row['id'], node_type='address', labels=row[dst+'_labels'] if row[dst+'_labels'] is not None else [], received=make_values( value=row[dst+'_properties'].total_received.value, eur=row[dst+'_properties'].total_received.eur, usd=row[dst+'_properties'].total_received.usd), estimated_value=make_values( value=row['estimated_value'].value, eur=row['estimated_value'].eur, usd=row['estimated_value'].usd), balance=convert_value(balance, rates), no_txs=row['no_transactions'])) return Neighbors(next_page=paging_state, neighbors=relations)
def get_currency_statistics(currency, version=None): db = get_connection() result = db.get_currency_statistics(currency) if result is None: raise ValueError('statistics for currency {} not found' .format(currency)) tstamp = datetime.utcfromtimestamp(result.timestamp) \ .strftime("%Y-%m-%d %H:%M:%S") return CurrencyStats( name=currency, no_blocks=result.no_blocks, no_address_relations=result.no_address_relations, no_addresses=result.no_addresses, no_entities=result.no_clusters, no_txs=result.no_transactions, no_labels=result.no_tags, timestamp=result.timestamp, tools=[], notes=[], data_sources=[StatsLedger( visible_name=currency.upper() + ' Blockchain', id=currency + '_ledger', version=StatsLedgerVersion( nr=str(result.no_blocks), timestamp=tstamp), report_uuid=currency + '_ledger')] )
def list_matching_txs(currency, expression, leading_zeros): db = get_connection() results = db.list_matching_txs(currency, expression, leading_zeros) txs = ["0" * leading_zeros + str(hex(int.from_bytes(row.tx_hash, byteorder="big")))[2:] for row in results] return [tx for tx in txs if tx.startswith(expression)]
def get_block(currency, height) -> Block: db = get_connection() row = db.get_block(currency, height) if not row: raise RuntimeError("Block {} not found".format(height)) return Block(height=row.height, block_hash=row.block_hash.hex(), no_txs=row.no_transactions, timestamp=row.timestamp)
def get_tx(currency, tx_hash): db = get_connection() result = db.get_tx(currency, tx_hash) if result is None: raise RuntimeError('Transaction {} in keyspace {} not found' .format(tx_hash, currency)) rates = get_rates(currency, result.height)['rates'] return from_row(result, rates)
def list_txs(currency, page=None): db = get_connection() results, paging_state = db.list_txs(currency, page) heights = [row.height for row in results] rates = list_rates(currency, heights) tx_list = [from_row(row, rates[row.height]) for row in results] return Txs(next_page=paging_state, txs=tx_list)
def get_address_entity_id(currency, address): db = get_connection() result = db.get_address_entity_id(currency, address) # from address to entity id only if result is None: raise RuntimeError( 'cluster for address {} in currency {} not found'.format( address, currency)) return result.cluster
def list_rates(currency, heights): db = get_connection() rates = db.list_rates(currency, heights) height_rates = dict() # key: height, value: {'eur': 0, 'usd':0} for rate in rates: height_rates[rate['height']] = { k: v for k, v in rate.items() if k != 'height' } return height_rates
def list_concepts(taxonomy): db = get_connection() rows = db.list_concepts(taxonomy) return [ Concept(id=row.id, label=row.label, description=row.description, taxonomy=row.taxonomy, uri=row.uri) for row in rows ]
def list_blocks(currency, page=None): db = get_connection() results, paging_state = db.list_blocks(currency, page) block_list = [ Block(height=row.height, block_hash=row.block_hash.hex(), no_txs=row.no_transactions, timestamp=row.timestamp) for row in results.current_rows ] return Blocks(paging_state, block_list)
def search_entity_neighbors(currency, entity, direction, key, value, depth, breadth, skip_num_addresses=None): # noqa: E501 params = dict() db = get_connection() if 'category' in key: params['category'] = value[0] elif 'total_received' in key or 'balance' in key: [curr, min_value, *max_value] = value max_value = max_value[0] if len(max_value) > 0 else None if min_value > max_value: raise ValueError('Min must not be greater than max') elif curr not in ['value', 'eur', 'usd']: raise ValueError('Currency must be one of "value", "eur" or ' '"usd"') params['field'] = (key, curr, min_value, max_value) elif 'addresses' in key: addresses_list = [] for address in value: e = db.get_address_entity_id(currency, address) if e: addresses_list.append({"address": address, "entity": e}) else: raise RuntimeError( "Entity of address {} not found in currency {}".format( address, currency)) params['addresses'] = addresses_list result = \ recursive_search(currency, entity, params, breadth, depth, skip_num_addresses, direction) def add_tag_coherence(paths): if not paths: return for path in paths: path.node.tag_coherence = compute_tag_coherence( t.label for t in path.node.tags) add_tag_coherence(path.paths) add_tag_coherence(result) return SearchPaths(paths=result)
def list_entity_tags(currency, entity): db = get_connection() tags = db.list_entity_tags(currency, entity) return [ Tag(label=row.label, address=row.address, category=row.category, abuse=row.abuse, tagpack_uri=row.tagpack_uri, source=row.source, lastmod=row.lastmod, active=True, currency=currency) for row in tags ]
def get_address_entity(currency, address): # from address to complete entity stats e = RuntimeError('Entity for address {} not found'.format(address)) db = get_connection() entity_id = db.get_address_entity_id(currency, address) if entity_id is None: raise e result = get_entity_with_tags(currency, entity_id) if result is None: raise e return result
def list_address_links(currency, address, neighbor): db = get_connection() links = db.list_address_links(currency, address, neighbor) heights = [row['height'] for row in links] rates = list_rates(currency, heights) return [Link(tx_hash=e['tx_hash'], height=e['height'], timestamp=e['timestamp'], input_value=convert_value( e['input_value'], rates[e['height']]), output_value=convert_value( e['output_value'], rates[e['height']]), ) for e in links]
def get_rates(currency, height=None): if height is None: height = get_currency_statistics(currency).no_blocks - 1 db = get_connection() r = db.get_rates(currency, height) if r is None: raise ValueError("Cannot find height {} in currency {}".format( height, currency)) return { 'height': r['height'], 'rates': {k: v for k, v in r.items() if k != 'height'} }
def list_tags(label, currency=None): db = get_connection() label = alphanumeric_lower(label) tags = db.list_tags(label, currency) return [ Tag(address=row.address, label=row.label, category=row.category, abuse=row.abuse, tagpack_uri=row.tagpack_uri, source=row.source, lastmod=row.lastmod, active=row.active_address, currency=row.currency) for row in tags ]
def list_address_txs(currency, address, page=None, pagesize=None): db = get_connection() results, paging_state = \ db.list_address_txs(currency, address, page, pagesize) address_txs = [] if results: heights = [row.height for row in results] rates = list_rates(currency, heights) address_txs = [AddressTx( address=address, height=row.height, timestamp=row.timestamp, tx_hash=row.tx_hash.hex(), value=convert_value(row.value, rates[row.height]) ) for row in results] return AddressTxs(next_page=paging_state, address_txs=address_txs)
def list_labels(currency, expression): # Normalize label expression_norm = alphanumeric_lower(expression) db = get_connection() result = db.list_labels(currency, expression_norm) if currency: return list( dict.fromkeys([ row.label for row in result if row.label_norm.startswith(expression_norm) and row.currency.lower() == currency ])) return list( dict.fromkeys([ row.label for row in result if row.label_norm.startswith(expression_norm) ]))
def list_block_txs(currency, height): db = get_connection() result = db.list_block_txs(currency, height) if result is None: raise RuntimeError("Block {} not found".format(height)) rates = get_rates(currency, height) tx_summaries = \ [BlockTxSummary( no_inputs=tx.no_inputs, no_outputs=tx.no_outputs, total_input=convert_value(tx.total_input, rates['rates']), total_output=convert_value(tx.total_output, rates['rates']), tx_hash=tx.tx_hash.hex() ) for tx in result.txs] return BlockTxs(height, tx_summaries)
def list_address_tags(currency, address): db = get_connection() results = db.list_address_tags(currency, address) if results is None: return [] address_tags = [ Tag(label=row.label, address=row.address, category=row.category, abuse=row.abuse, tagpack_uri=row.tagpack_uri, source=row.source, lastmod=row.lastmod, active=True, currency=currency) for row in results ] return address_tags
def search(q, currency=None, limit=None): db = get_connection() currencies = db.get_supported_currencies() leading_zeros = 0 pos = 0 # leading zeros will be lost when casting to int while q[pos] == "0": pos += 1 leading_zeros += 1 q = q.strip() result = SearchResult(currencies=[], labels=[]) prefix_lengths = db.get_prefix_lengths() for currency in currencies: element = SearchResultByCurrency(currency=currency, addresses=[], txs=[]) # Look for addresses and transactions if len(q) >= prefix_lengths['tx']: txs = list_matching_txs(currency, q, leading_zeros) element.txs = txs[:limit] if len(q) >= prefix_lengths['address']: addresses = list_matching_addresses(currency, q) element.addresses = addresses[:limit] result.currencies.append(element) if len(q) >= prefix_lengths['label']: labels = list_labels(currency, q)[:limit] if labels: result.labels += labels return result
def list_entity_neighbors(currency, entity, direction, targets=None, page=None, pagesize=None): db = get_connection() is_outgoing = "out" in direction results, paging_state = db.list_entity_neighbors(currency, entity, is_outgoing, targets, page, pagesize) rates = get_rates(currency)['rates'] relations = [] dst = 'dst' if is_outgoing else 'src' for row in results: balance = compute_balance( getattr(row, dst + '_properties').total_received.value, getattr(row, dst + '_properties').total_spent.value) relations.append( Neighbor( id=getattr(row, dst + '_cluster'), node_type='entity', labels=getattr(row, dst + '_labels') if getattr( row, dst + '_labels') is not None else [], received=make_values( value=getattr(row, dst + '_properties').total_received.value, eur=getattr(row, dst + '_properties').total_received.eur, usd=getattr(row, dst + '_properties').total_received.usd), estimated_value=make_values(value=row.value.value, eur=row.value.eur, usd=row.value.usd), balance=convert_value(balance, rates), no_txs=row.no_transactions)) return Neighbors(next_page=paging_state, neighbors=relations)
def list_taxonomies(): db = get_connection() rows = db.list_taxonomies() return [Taxonomy(taxonomy=row.key, uri=row.uri) for row in rows]
def list_matching_addresses(currency, expression): db = get_connection() return db.list_matching_addresses(currency, expression)