import wasmtime import struct import math import os import ctypes from pathlib import Path class Solver: def __init__(self): """Initialize the WASM solver""" # Try to find the WASM file current_dir = Path(__file__).parent go_wasm_path = Path(__file__).parent.parent.parent / 'deepseek4free' / 'pkg' / 'solver' / 'sha3_wasm_bg.7b9ca65ddd.wasm' if go_wasm_path.exists(): with open(go_wasm_path, 'rb') as f: wasm_bytes = f.read() else: raise FileNotFoundError(f"WASM file not found at {go_wasm_path}") engine = wasmtime.Engine() self.module = wasmtime.Module(engine, wasm_bytes) self.store = wasmtime.Store(engine) self.linker = wasmtime.Linker(engine) self.linker.define_wasi() self.instance = self.linker.instantiate(self.store, self.module) # Get exports - handle both old and new wasmtime-py API exports = self.instance.exports(self.store) # Get memory export try: # Try direct attribute access first self.memory = exports.memory except AttributeError: # Try dict-like access try: self.memory = exports['memory'] except (KeyError, TypeError): # Try get_export method mem_extern = self.instance.get_export(self.store, 'memory') if mem_extern and hasattr(mem_extern, 'memory'): self.memory = mem_extern.memory else: raise RuntimeError("Could not find memory export in WASM module") # Initialize functions - with error handling try: self.alloc_fn = exports.__wbindgen_export_0 except AttributeError: self.alloc_fn = exports['__wbindgen_export_0'] try: self.stack_ptr_fn = exports.__wbindgen_add_to_stack_pointer except AttributeError: self.stack_ptr_fn = exports['__wbindgen_add_to_stack_pointer'] try: self.solve_fn = exports.wasm_solve except AttributeError: self.solve_fn = exports['wasm_solve'] def _write_to_memory(self, text: str) -> tuple[int, int]: """Write a string to WASM memory and return pointer and length""" text_bytes = text.encode('utf-8') length = len(text_bytes) # Allocate memory - pass store as first argument ptr = self.alloc_fn(self.store, length, 1) print(f"[DEBUG] Allocated memory at ptr={ptr}, length={length}") # Get memory data pointer mem_ptr = self.memory.data_ptr(self.store) print(f"[DEBUG] Memory pointer type: {type(mem_ptr)}") # Write to memory - mem_ptr is a ctypes pointer, can index it directly try: for i, byte in enumerate(text_bytes): mem_ptr[ptr + i] = byte print(f"[DEBUG] Successfully wrote {length} bytes to memory") except TypeError as e: print(f"[DEBUG] Error writing to memory: {e}") # Try alternative approach with ctypes address try: addr = ctypes.cast(mem_ptr, ctypes.c_void_p).value print(f"[DEBUG] Memory address: {addr}") buffer = (ctypes.c_ubyte * length).from_address(addr + ptr) for i, byte in enumerate(text_bytes): buffer[i] = byte print(f"[DEBUG] Successfully wrote {length} bytes using ctypes buffer") except Exception as e2: print(f"[DEBUG] Also failed with ctypes: {e2}") raise return ptr, length def _read_memory(self, ptr: int, length: int) -> bytes: """Read bytes from WASM memory""" mem_ptr = self.memory.data_ptr(self.store) print(f"[DEBUG] Reading {length} bytes from ptr={ptr}, memory_ptr type={type(mem_ptr)}") try: # Try direct indexing of ctypes pointer result = [] for i in range(length): result.append(mem_ptr[ptr + i]) return bytes(result) except TypeError as e: print(f"[DEBUG] Error reading with direct indexing: {e}") # Try converting to address and using ctypes try: addr = ctypes.cast(mem_ptr, ctypes.c_void_p).value print(f"[DEBUG] Memory address: {addr}") buffer = (ctypes.c_ubyte * length).from_address(addr + ptr) return bytes(buffer) except Exception as e2: print(f"[DEBUG] Also failed with ctypes: {e2}") raise def calculate_hash(self, challenge: str, salt: str, difficulty: int, expire_at: int) -> int: """Calculate hash using WASM solver""" print(f"[DEBUG] calculate_hash called with challenge={challenge[:20]}..., salt={salt}, difficulty={difficulty}") prefix = f"{salt}_{expire_at}_" # Adjust stack pointer - pass store as first argument retptr = self.stack_ptr_fn(self.store, -16) print(f"[DEBUG] Stack pointer adjusted, retptr={retptr}") # Write to memory challenge_ptr, challenge_len = self._write_to_memory(challenge) prefix_ptr, prefix_len = self._write_to_memory(prefix) print(f"[DEBUG] Wrote challenge at {challenge_ptr}, prefix at {prefix_ptr}") # Call solve function - pass store as first argument print(f"[DEBUG] Calling solve function with retptr={retptr}, challenge_ptr={challenge_ptr}, difficulty={difficulty}") self.solve_fn(self.store, retptr, challenge_ptr, challenge_len, prefix_ptr, prefix_len, float(difficulty)) # Read result from memory status_bytes = self._read_memory(retptr, 4) status = struct.unpack('