Spaces:
Runtime error
Runtime error
alex n
commited on
Commit
Β·
c16ebf6
1
Parent(s):
57bdb5e
added data veridication
Browse files- app.py +1 -1
- pyproject.toml +0 -13
- axoninfo.py β testing/axoninfo.py +0 -0
- testing/datavalidation.py +0 -0
- testing/fetch_bits.py +135 -0
- testing/validatorbyte.py +34 -0
- validate_rule30.py +69 -0
app.py
CHANGED
@@ -260,7 +260,7 @@ custom_css = """
|
|
260 |
|
261 |
with gr.Blocks(title="π SN36 Validator States", css=custom_css) as demo:
|
262 |
gr.Markdown("""
|
263 |
-
<h1 style="text-align: center; font-size: 3em; margin: 0.5em 0;">
|
264 |
π SN36 Validator States
|
265 |
</h1>
|
266 |
""", elem_id="title")
|
|
|
260 |
|
261 |
with gr.Blocks(title="π SN36 Validator States", css=custom_css) as demo:
|
262 |
gr.Markdown("""
|
263 |
+
<h1 style="text-align: center; font-size: 3em; margin: 0.5em 0; width: 100%; display: block;">
|
264 |
π SN36 Validator States
|
265 |
</h1>
|
266 |
""", elem_id="title")
|
pyproject.toml
DELETED
@@ -1,13 +0,0 @@
|
|
1 |
-
[tool.ruff]
|
2 |
-
# Enable pycodestyle (`E`) and Pyflakes (`F`) codes by default.
|
3 |
-
select = ["E", "F"]
|
4 |
-
ignore = ["E501"] # line too long (black is taking care of this)
|
5 |
-
line-length = 119
|
6 |
-
fixable = ["A", "B", "C", "D", "E", "F", "G", "I", "N", "Q", "S", "T", "W", "ANN", "ARG", "BLE", "COM", "DJ", "DTZ", "EM", "ERA", "EXE", "FBT", "ICN", "INP", "ISC", "NPY", "PD", "PGH", "PIE", "PL", "PT", "PTH", "PYI", "RET", "RSE", "RUF", "SIM", "SLF", "TCH", "TID", "TRY", "UP", "YTT"]
|
7 |
-
|
8 |
-
[tool.isort]
|
9 |
-
profile = "black"
|
10 |
-
line_length = 119
|
11 |
-
|
12 |
-
[tool.black]
|
13 |
-
line-length = 119
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
axoninfo.py β testing/axoninfo.py
RENAMED
File without changes
|
testing/datavalidation.py
ADDED
File without changes
|
testing/fetch_bits.py
ADDED
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import aiohttp
|
2 |
+
import asyncio
|
3 |
+
import numpy as np
|
4 |
+
|
5 |
+
def generate_middle_column(steps: int) -> bytes:
|
6 |
+
"""Generate the middle column of Rule 30 for n steps and return as bytes"""
|
7 |
+
print(f"Starting Rule 30 generation for {steps:,} steps...")
|
8 |
+
|
9 |
+
# Use boolean array for faster operations
|
10 |
+
width = steps + 2 # Only need 1 cell padding on each side
|
11 |
+
state = np.zeros(width, dtype=bool)
|
12 |
+
state[width//2] = True
|
13 |
+
|
14 |
+
# Pre-allocate array for ALL middle column bits
|
15 |
+
bits = np.zeros(steps, dtype=bool)
|
16 |
+
bits[0] = True # First bit is always 1
|
17 |
+
|
18 |
+
# Create views for faster access
|
19 |
+
left = state[:-2]
|
20 |
+
center = state[1:-1]
|
21 |
+
right = state[2:]
|
22 |
+
|
23 |
+
# Progress tracking
|
24 |
+
update_every = max(1, steps // 1000)
|
25 |
+
|
26 |
+
# Main loop - generate each step
|
27 |
+
for i in range(1, steps):
|
28 |
+
if i % update_every == 0:
|
29 |
+
print(f'\rGenerating... {(i/steps)*100:3.1f}% ({i:,}/{steps:,})', end='', flush=True)
|
30 |
+
|
31 |
+
# Store middle bit at position i in our pre-allocated array
|
32 |
+
bits[i] = center[steps//2] # This is where we save each middle column bit
|
33 |
+
|
34 |
+
# Rule 30: next = left XOR (center OR right)
|
35 |
+
# Update center in-place for next iteration
|
36 |
+
np.logical_xor(left, np.logical_or(center, right), out=center)
|
37 |
+
|
38 |
+
# Shift views for next iteration
|
39 |
+
left[1:] = left[:-1]
|
40 |
+
right[:-1] = right[1:]
|
41 |
+
left[0] = False
|
42 |
+
right[-1] = False
|
43 |
+
|
44 |
+
print(f'\rGeneration complete: {steps:,} steps')
|
45 |
+
|
46 |
+
# Convert all collected bits to bytes at once
|
47 |
+
byte_array = np.packbits(bits) # This packs our middle column bits into bytes
|
48 |
+
return bytes(byte_array)
|
49 |
+
|
50 |
+
async def fetch_validator_bits(ip: str = "65.109.145.104", port: int = 8091, num_bytes: int = 7) -> tuple[int, bytes, int]:
|
51 |
+
"""Fetch step and most recent bytes from validator API"""
|
52 |
+
print("Starting API fetch...")
|
53 |
+
async with aiohttp.ClientSession() as session:
|
54 |
+
# Get step
|
55 |
+
step_url = f"http://{ip}:{port}/step"
|
56 |
+
async with session.get(step_url, timeout=5) as resp:
|
57 |
+
if resp.status != 200:
|
58 |
+
raise Exception(f"Failed to get step: {resp.status}")
|
59 |
+
step = await resp.json()
|
60 |
+
print(f"Got step: {step}")
|
61 |
+
if step <= 0:
|
62 |
+
raise Exception(f"Invalid step value: {step}")
|
63 |
+
|
64 |
+
# Get only the most recent bytes
|
65 |
+
bits_url = f"http://{ip}:{port}/bits"
|
66 |
+
end_byte = (step + 7) // 8
|
67 |
+
start_byte = max(0, end_byte - num_bytes)
|
68 |
+
headers = {'Range': f'bytes={start_byte}-{end_byte-1}'}
|
69 |
+
print(f"Requesting bytes {start_byte}-{end_byte-1}...")
|
70 |
+
|
71 |
+
async with session.get(bits_url, headers=headers, timeout=5) as resp:
|
72 |
+
if resp.status != 206:
|
73 |
+
raise Exception(f"Failed to get bits: {resp.status}")
|
74 |
+
|
75 |
+
bytes_data = await resp.read()
|
76 |
+
if not bytes_data:
|
77 |
+
raise Exception("No data received")
|
78 |
+
|
79 |
+
# Remove trailing zero bytes
|
80 |
+
while bytes_data and bytes_data[-1] == 0:
|
81 |
+
bytes_data = bytes_data[:-1]
|
82 |
+
|
83 |
+
print(f"Got {len(bytes_data)} non-zero bytes")
|
84 |
+
return step, bytes_data, start_byte
|
85 |
+
|
86 |
+
async def main():
|
87 |
+
try:
|
88 |
+
# Get most recent bytes from API
|
89 |
+
step, api_bytes, start_pos = await fetch_validator_bits(num_bytes=7)
|
90 |
+
print("\nAPI bytes details:")
|
91 |
+
print(f"Step: {step}")
|
92 |
+
print(f"Starting from byte position: {start_pos}")
|
93 |
+
|
94 |
+
# Skip the last byte from API for comparison
|
95 |
+
api_bytes = api_bytes[:-1]
|
96 |
+
|
97 |
+
# Generate matching bytes
|
98 |
+
print("\nGenerating Rule 30 bytes...")
|
99 |
+
test_bytes = generate_middle_column(step)
|
100 |
+
|
101 |
+
# Calculate positions
|
102 |
+
total_bytes = (step + 7) // 8
|
103 |
+
# Get bytes from the same positions as API bytes
|
104 |
+
test_bytes = test_bytes[start_pos:start_pos + len(api_bytes)]
|
105 |
+
|
106 |
+
# Show the bytes we're comparing
|
107 |
+
print("\nBytes being compared:")
|
108 |
+
print("API bytes:")
|
109 |
+
for i, b in enumerate(api_bytes):
|
110 |
+
abs_pos = start_pos + i
|
111 |
+
print(f"Position {abs_pos}: {hex(b)} (binary: {format(b, '08b')})")
|
112 |
+
|
113 |
+
print("\nGenerated bytes:")
|
114 |
+
for i, b in enumerate(test_bytes):
|
115 |
+
abs_pos = start_pos + i
|
116 |
+
print(f"Position {abs_pos}: {hex(b)} (binary: {format(b, '08b')})")
|
117 |
+
|
118 |
+
# Compare bytes
|
119 |
+
if api_bytes == test_bytes:
|
120 |
+
print("\nβ
Bytes match")
|
121 |
+
else:
|
122 |
+
print("\nβ Bytes differ")
|
123 |
+
for i, (a, b) in enumerate(zip(api_bytes, test_bytes)):
|
124 |
+
abs_pos = start_pos + i
|
125 |
+
if a != b:
|
126 |
+
print(f"\nFirst difference at position {abs_pos}:")
|
127 |
+
print(f"API: {hex(a)} (binary: {format(a, '08b')})")
|
128 |
+
print(f"Generated: {hex(b)} (binary: {format(b, '08b')})")
|
129 |
+
break
|
130 |
+
|
131 |
+
except Exception as e:
|
132 |
+
print(f"Error: {str(e)}")
|
133 |
+
|
134 |
+
if __name__ == "__main__":
|
135 |
+
asyncio.run(main())
|
testing/validatorbyte.py
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import asyncio
|
2 |
+
import aiohttp
|
3 |
+
|
4 |
+
async def get_nth_byte(n: int, ip: str = "65.109.145.104", port: int = 8091) -> bytes:
|
5 |
+
"""Fetch the nth byte from validator API"""
|
6 |
+
print(f"Fetching byte at position {n}")
|
7 |
+
|
8 |
+
async with aiohttp.ClientSession() as session:
|
9 |
+
# Get just the single byte we want
|
10 |
+
bits_url = f"http://{ip}:{port}/bits"
|
11 |
+
headers = {'Range': f'bytes={n}-{n}'}
|
12 |
+
|
13 |
+
async with session.get(bits_url, headers=headers, timeout=5) as resp:
|
14 |
+
if resp.status != 206:
|
15 |
+
raise Exception(f"Failed to get byte: {resp.status}")
|
16 |
+
|
17 |
+
byte_data = await resp.read()
|
18 |
+
if not byte_data:
|
19 |
+
raise Exception("No data received")
|
20 |
+
|
21 |
+
print(f"Got byte: {hex(byte_data[0])} (binary: {format(byte_data[0], '08b')})")
|
22 |
+
return byte_data
|
23 |
+
|
24 |
+
async def main():
|
25 |
+
try:
|
26 |
+
# Get byte at position n
|
27 |
+
n = 167371 # Change this to get different bytes
|
28 |
+
byte_data = await get_nth_byte(n)
|
29 |
+
|
30 |
+
except Exception as e:
|
31 |
+
print(f"Error: {str(e)}")
|
32 |
+
|
33 |
+
if __name__ == "__main__":
|
34 |
+
asyncio.run(main())
|
validate_rule30.py
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import argparse
|
2 |
+
from typing import Optional
|
3 |
+
|
4 |
+
def get_next_bit(left: str, center: str, right: str) -> str:
|
5 |
+
"""Rule 30 implementation:
|
6 |
+
111 -> 0
|
7 |
+
110 -> 0
|
8 |
+
101 -> 0
|
9 |
+
100 -> 1
|
10 |
+
011 -> 1
|
11 |
+
010 -> 1
|
12 |
+
001 -> 1
|
13 |
+
000 -> 0
|
14 |
+
"""
|
15 |
+
pattern = left + center + right
|
16 |
+
rule30_map = {
|
17 |
+
"111": "0", "110": "0", "101": "0", "100": "1",
|
18 |
+
"011": "1", "010": "1", "001": "1", "000": "0"
|
19 |
+
}
|
20 |
+
return rule30_map[pattern]
|
21 |
+
|
22 |
+
def validate_sequence(bits: str) -> tuple[bool, Optional[int]]:
|
23 |
+
"""Validate if a sequence follows Rule 30.
|
24 |
+
Returns (is_valid, first_error_position)
|
25 |
+
"""
|
26 |
+
if not all(bit in '01' for bit in bits):
|
27 |
+
return False, 0
|
28 |
+
|
29 |
+
# Pad with zeros for edge cases
|
30 |
+
padded = '0' + bits + '0'
|
31 |
+
|
32 |
+
for i in range(1, len(bits) + 1):
|
33 |
+
expected = get_next_bit(
|
34 |
+
padded[i-1],
|
35 |
+
padded[i],
|
36 |
+
padded[i+1]
|
37 |
+
)
|
38 |
+
if i < len(bits) and bits[i] != expected:
|
39 |
+
return False, i
|
40 |
+
|
41 |
+
return True, None
|
42 |
+
|
43 |
+
def main():
|
44 |
+
parser = argparse.ArgumentParser(description='Validate a binary sequence against Rule 30')
|
45 |
+
parser.add_argument('file', help='Path to file containing binary sequence')
|
46 |
+
args = parser.parse_args()
|
47 |
+
|
48 |
+
try:
|
49 |
+
with open(args.file, 'r') as f:
|
50 |
+
bits = f.read().strip()
|
51 |
+
|
52 |
+
is_valid, error_pos = validate_sequence(bits)
|
53 |
+
|
54 |
+
if is_valid:
|
55 |
+
print("β
Sequence follows Rule 30")
|
56 |
+
return 0
|
57 |
+
else:
|
58 |
+
print(f"β Sequence violates Rule 30 at position {error_pos}")
|
59 |
+
return 1
|
60 |
+
|
61 |
+
except FileNotFoundError:
|
62 |
+
print(f"Error: File {args.file} not found")
|
63 |
+
return 2
|
64 |
+
except Exception as e:
|
65 |
+
print(f"Error: {str(e)}")
|
66 |
+
return 3
|
67 |
+
|
68 |
+
if __name__ == "__main__":
|
69 |
+
exit(main())
|