Spaces:
Runtime error
Runtime error
import aiohttp | |
import asyncio | |
import numpy as np | |
def generate_middle_column(steps: int) -> bytes: | |
"""Generate the middle column of Rule 30 for n steps and return as bytes""" | |
print(f"Starting Rule 30 generation for {steps:,} steps...") | |
# Use boolean array for faster operations | |
width = steps + 2 # Only need 1 cell padding on each side | |
state = np.zeros(width, dtype=bool) | |
state[width//2] = True | |
# Pre-allocate array for ALL middle column bits | |
bits = np.zeros(steps, dtype=bool) | |
bits[0] = True # First bit is always 1 | |
# Create views for faster access | |
left = state[:-2] | |
center = state[1:-1] | |
right = state[2:] | |
# Progress tracking | |
update_every = max(1, steps // 1000) | |
# Main loop - generate each step | |
for i in range(1, steps): | |
if i % update_every == 0: | |
print(f'\rGenerating... {(i/steps)*100:3.1f}% ({i:,}/{steps:,})', end='', flush=True) | |
# Store middle bit at position i in our pre-allocated array | |
bits[i] = center[steps//2] # This is where we save each middle column bit | |
# Rule 30: next = left XOR (center OR right) | |
# Update center in-place for next iteration | |
np.logical_xor(left, np.logical_or(center, right), out=center) | |
# Shift views for next iteration | |
left[1:] = left[:-1] | |
right[:-1] = right[1:] | |
left[0] = False | |
right[-1] = False | |
print(f'\rGeneration complete: {steps:,} steps') | |
# Convert all collected bits to bytes at once | |
byte_array = np.packbits(bits) # This packs our middle column bits into bytes | |
return bytes(byte_array) | |
async def fetch_validator_bits(ip: str = "65.109.145.104", port: int = 8091, num_bytes: int = 7) -> tuple[int, bytes, int]: | |
"""Fetch step and most recent bytes from validator API""" | |
print("Starting API fetch...") | |
async with aiohttp.ClientSession() as session: | |
# Get step | |
step_url = f"http://{ip}:{port}/step" | |
async with session.get(step_url, timeout=5) as resp: | |
if resp.status != 200: | |
raise Exception(f"Failed to get step: {resp.status}") | |
step = await resp.json() | |
print(f"Got step: {step}") | |
if step <= 0: | |
raise Exception(f"Invalid step value: {step}") | |
# Get only the most recent bytes | |
bits_url = f"http://{ip}:{port}/bits" | |
end_byte = (step + 7) // 8 | |
start_byte = max(0, end_byte - num_bytes) | |
headers = {'Range': f'bytes={start_byte}-{end_byte-1}'} | |
print(f"Requesting bytes {start_byte}-{end_byte-1}...") | |
async with session.get(bits_url, headers=headers, timeout=5) as resp: | |
if resp.status != 206: | |
raise Exception(f"Failed to get bits: {resp.status}") | |
bytes_data = await resp.read() | |
if not bytes_data: | |
raise Exception("No data received") | |
# Remove trailing zero bytes | |
while bytes_data and bytes_data[-1] == 0: | |
bytes_data = bytes_data[:-1] | |
print(f"Got {len(bytes_data)} non-zero bytes") | |
return step, bytes_data, start_byte | |
async def main(): | |
try: | |
# Get most recent bytes from API | |
step, api_bytes, start_pos = await fetch_validator_bits(num_bytes=7) | |
print("\nAPI bytes details:") | |
print(f"Step: {step}") | |
print(f"Starting from byte position: {start_pos}") | |
# Skip the last byte from API for comparison | |
api_bytes = api_bytes[:-1] | |
# Generate matching bytes | |
print("\nGenerating Rule 30 bytes...") | |
test_bytes = generate_middle_column(step) | |
# Calculate positions | |
total_bytes = (step + 7) // 8 | |
# Get bytes from the same positions as API bytes | |
test_bytes = test_bytes[start_pos:start_pos + len(api_bytes)] | |
# Show the bytes we're comparing | |
print("\nBytes being compared:") | |
print("API bytes:") | |
for i, b in enumerate(api_bytes): | |
abs_pos = start_pos + i | |
print(f"Position {abs_pos}: {hex(b)} (binary: {format(b, '08b')})") | |
print("\nGenerated bytes:") | |
for i, b in enumerate(test_bytes): | |
abs_pos = start_pos + i | |
print(f"Position {abs_pos}: {hex(b)} (binary: {format(b, '08b')})") | |
# Compare bytes | |
if api_bytes == test_bytes: | |
print("\n✅ Bytes match") | |
else: | |
print("\n❌ Bytes differ") | |
for i, (a, b) in enumerate(zip(api_bytes, test_bytes)): | |
abs_pos = start_pos + i | |
if a != b: | |
print(f"\nFirst difference at position {abs_pos}:") | |
print(f"API: {hex(a)} (binary: {format(a, '08b')})") | |
print(f"Generated: {hex(b)} (binary: {format(b, '08b')})") | |
break | |
except Exception as e: | |
print(f"Error: {str(e)}") | |
if __name__ == "__main__": | |
asyncio.run(main()) |