import sys import json import logging from PyQt5.QtWidgets import ( QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QTextEdit, QTabWidget, QTreeWidget, QTreeWidgetItem, QMessageBox ) from PyQt5.QtGui import QFont, QIcon from PyQt5.QtCore import Qt, QThread, pyqtSignal # Import the P2SH Transaction Debugger from p2sh_transaction_debugger import P2SHTransactionDebugger class TransactionDebuggerThread(QThread): """ Background thread for processing transaction debugging to prevent UI freezing """ debug_complete = pyqtSignal(dict) error_occurred = pyqtSignal(str) def __init__(self, debugger, tx_hash, network): super().__init__() self.debugger = debugger self.tx_hash = tx_hash self.network = network def run(self): try: # Temporarily switch network if needed original_network = self.debugger.network self.debugger.network = self.network # Debug the transaction tx_details = self.debugger.debug_p2sh_transaction(self.tx_hash) # Restore original network self.debugger.network = original_network if tx_details: self.debug_complete.emit(tx_details) else: self.error_occurred.emit("Failed to retrieve transaction details") except Exception as e: self.error_occurred.emit(str(e)) class P2SHDebuggerApp(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("P2SH Transaction Debugger") self.setGeometry(100, 100, 800, 600) # Initialize debugger self.debugger = P2SHTransactionDebugger() # Setup main UI self.init_ui() def init_ui(self): """ Create the main user interface """ # Central widget and main layout central_widget = QWidget() main_layout = QVBoxLayout() central_widget.setLayout(main_layout) self.setCentralWidget(central_widget) # Transaction input section input_layout = QHBoxLayout() # Network selection self.network_input = QLineEdit() self.network_input.setPlaceholderText("Network (mainnet/testnet)") self.network_input.setText("mainnet") input_layout.addWidget(self.network_input) # Transaction hash input self.tx_hash_input = QLineEdit() self.tx_hash_input.setPlaceholderText("Enter Bitcoin Transaction Hash") input_layout.addWidget(self.tx_hash_input) # Transaction serialData input self.tx_data_input = QLineEdit() self.tx_data_input.setPlaceholderText("Enter Serialized Bitcoin Transaction Data") input_layout.addWidget(self.tx_data_input) # Debug button debug_button = QPushButton("Debug Transaction") debug_button.clicked.connect(self.start_transaction_debug) input_layout.addWidget(debug_button) main_layout.addLayout(input_layout) # Tabs for different views self.tabs = QTabWidget() main_layout.addWidget(self.tabs) # Create tabs self.details_tab = QTextEdit() self.details_tab.setReadOnly(True) self.tree_tab = QTreeWidget() self.tree_tab.setHeaderLabel("Transaction Structure") self.tabs.addTab(self.details_tab, "Detailed View") self.tabs.addTab(self.tree_tab, "Structured View") def start_transaction_debug(self): """ Initiate transaction debugging process """ # Validate inputs tx_hash = self.tx_hash_input.text().strip() network = self.network_input.text().strip().lower() if not tx_hash: QMessageBox.warning(self, "Input Error", "Please enter a transaction hash") return if network not in ['mainnet', 'testnet']: QMessageBox.warning(self, "Network Error", "Invalid network. Use 'mainnet' or 'testnet'") return # Clear previous results self.details_tab.clear() self.tree_tab.clear() # Start debugging thread self.debug_thread = TransactionDebuggerThread( self.debugger, tx_hash, network ) self.debug_thread.debug_complete.connect(self.display_debug_results) self.debug_thread.error_occurred.connect(self.handle_debug_error) self.debug_thread.start() def display_debug_results(self, results): """ Display debugging results in both tabs """ # Detailed Text View self.details_tab.setPlainText( json.dumps(results, indent=2) ) # Structured Tree View self._populate_tree_view(results) def _populate_tree_view(self, results): """ Populate the tree view with transaction details """ self.tree_tab.clear() # Transaction hash root item root = QTreeWidgetItem(self.tree_tab, [f"Transaction: {results.get('transaction_hash', 'N/A')}"]) # Inputs section inputs_item = QTreeWidgetItem(root, ["Inputs"]) for idx, input_data in enumerate(results.get('inputs', [])): input_item = QTreeWidgetItem(inputs_item, [f"Input {idx+1}"]) for key, value in input_data.items(): QTreeWidgetItem(input_item, [f"{key}: {str(value)}"]) # Outputs section outputs_item = QTreeWidgetItem(root, ["Outputs"]) for idx, output_data in enumerate(results.get('outputs', [])): output_item = QTreeWidgetItem(outputs_item, [f"Output {idx+1}"]) for key, value in output_data.items(): QTreeWidgetItem(output_item, [f"{key}: {str(value)}"]) self.tree_tab.expandAll() def handle_debug_error(self, error_message): """ Handle errors during debugging process """ QMessageBox.critical( self, "Debugging Error", f"An error occurred: {error_message}" ) def main(): """ Main application entry point """ # Configure logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) # Create application app = QApplication(sys.argv) # Set application style app.setStyle('Fusion') # Modern, cross-platform style # Create and show main window debugger_app = P2SHDebuggerApp() debugger_app.show() # Execute the application sys.exit(app.exec_()) if __name__ == "__main__": main() # Required dependencies: # pip install PyQt5 requests base58