#!/usr/bin/env python3 """ Script per visualizzare i dati P2PK dal database Genera un report HTML interattivo """ import sqlite3 import sys from datetime import datetime from pathlib import Path class P2PKDatabaseViewer: def __init__(self, db_path: str = "bitcoin_p2pk_study.db"): self.db_path = db_path def check_database_exists(self) -> bool: """Verifica se il database esiste""" return Path(self.db_path).exists() def get_statistics(self) -> dict: """Ottieni statistiche dal database""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() stats = {} try: # Progresso scansione cursor.execute('SELECT last_scanned_block, total_p2pk_found FROM scan_progress WHERE id = 1') progress = cursor.fetchone() stats['last_block'] = progress[0] if progress else 0 stats['total_found'] = progress[1] if progress else 0 # Totale P2PK nel database cursor.execute('SELECT COUNT(*) FROM p2pk_addresses') stats['total_in_db'] = cursor.fetchone()[0] # Range blocchi cursor.execute('SELECT MIN(block_height), MAX(block_height) FROM p2pk_addresses') min_block, max_block = cursor.fetchone() stats['min_block'] = min_block if min_block is not None else 0 stats['max_block'] = max_block if max_block is not None else 0 # Blocchi unici con P2PK cursor.execute('SELECT COUNT(DISTINCT block_height) FROM p2pk_addresses') stats['unique_blocks'] = cursor.fetchone()[0] # Transazioni unique cursor.execute('SELECT COUNT(DISTINCT txid) FROM p2pk_addresses') stats['unique_txs'] = cursor.fetchone()[0] # P2PK non spesi (con saldo attuale) cursor.execute('SELECT COUNT(*) FROM p2pk_addresses WHERE is_unspent = 1') stats['unspent_count'] = cursor.fetchone()[0] # Valore totale - calcolo manuale per evitare overflow cursor.execute('SELECT value_satoshi FROM p2pk_addresses') all_values = cursor.fetchall() total_sat = 0.0 for (val,) in all_values: if val is not None: total_sat += float(val) stats['total_value_btc'] = total_sat / 100000000.0 stats['total_value_sat'] = int(total_sat) # Valore non speso cursor.execute('SELECT value_satoshi FROM p2pk_addresses WHERE is_unspent = 1') unspent_values = cursor.fetchall() unspent_sat = 0.0 for (val,) in unspent_values: if val is not None: unspent_sat += float(val) stats['unspent_value_btc'] = unspent_sat / 100000000.0 stats['unspent_value_sat'] = int(unspent_sat) # Conta chiavi compresse vs non compresse cursor.execute('SELECT scriptpubkey FROM p2pk_addresses') all_scripts = cursor.fetchall() compressed_count = 0 uncompressed_count = 0 for (script,) in all_scripts: if script and script.startswith('41') and len(script) == 134: uncompressed_count += 1 elif script and script.startswith('21') and len(script) == 70: compressed_count += 1 stats['compressed_count'] = compressed_count stats['uncompressed_count'] = uncompressed_count except Exception as e: print(f"โ ๏ธ Errore nel calcolo statistiche: {e}") import traceback traceback.print_exc() stats = { 'last_block': 0, 'total_found': 0, 'total_in_db': 0, 'min_block': 0, 'max_block': 0, 'unique_blocks': 0, 'total_value_btc': 0.0, 'total_value_sat': 0, 'unique_txs': 0, 'unspent_count': 0, 'unspent_value_btc': 0.0, 'unspent_value_sat': 0, 'compressed_count': 0, 'uncompressed_count': 0 } conn.close() return stats def get_all_p2pk(self, limit: int = None) -> list: """Ottieni tutti i P2PK dal database""" conn = sqlite3.connect(self.db_path) cursor = conn.cursor() query = ''' SELECT id, block_height, txid, output_index, scriptpubkey, value_satoshi, timestamp, is_unspent, last_checked FROM p2pk_addresses ORDER BY block_height ASC, id ASC ''' if limit: query += f' LIMIT {limit}' cursor.execute(query) results = cursor.fetchall() conn.close() return results def extract_pubkey_from_script(self, scriptpubkey: str) -> str: """Estrae la chiave pubblica dallo scriptPubKey""" if not scriptpubkey: return "" # P2PK non compresso: 41 + pubkey (130 hex chars) + ac if scriptpubkey.startswith('41') and len(scriptpubkey) == 134: return scriptpubkey[2:132] # Rimuovi 41 all'inizio e ac alla fine # P2PK compresso: 21 + pubkey (66 hex chars) + ac elif scriptpubkey.startswith('21') and len(scriptpubkey) == 70: return scriptpubkey[2:68] # Rimuovi 21 all'inizio e ac alla fine return scriptpubkey def _generate_table_html(self, p2pk_data: list) -> str: """Genera l'HTML della tabella""" if not p2pk_data: return '
| ID | Blocco | TXID | Output | Chiave Pubblica | Valore (BTC) | Stato UTXO | Timestamp |
|---|
Bitcoin Pay-to-Public-Key Transaction Scanner
Database: {self.db_path}