back32hash 5591: готово к тестам

Вроде как всё готово к тестам.
This commit is contained in:
AidarKC
2026-10-02 01:32:37 +03:00
parent e101e5c5f4
commit de8700f8e0
51 changed files with 337 additions and 18091 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ JWK используется только подготовщиком. Не по
- `prevHash` глобальной цепочки.
- `prevLineNumber/prevLineHash` канальной линии.
- ANS-104 signing/deepHash без сверки с серверной реализацией.
- `App=test5590` и `c=<canonical channel>` без согласованного изменения импортера/Viewer.
- текущий `App=<SHINE_PROTOCOL_NAMESPACE>` и `c=<canonical channel>` без согласованного изменения импортера/Viewer.
## Viewer
Viewer распознаёт Arweave URL в тексте POST и показывает изображения inline. Экран «Проверка данных» независимо считает SHA-256 Frame, проверяет доступные `prevHash` и `prevLineHash`, показывает отсутствие соседнего блока как «нет данных», а доказанное несовпадение — как ошибку. Подпись ANS-104 нельзя помечать локально проверенной, если gateway не предоставил сырую подпись DataItem.
+23
View File
@@ -0,0 +1,23 @@
from pathlib import Path
import re
_UI_PROTOCOL_TAGS = Path(__file__).resolve().parents[2] / 'shine-UI' / 'js' / 'services' / 'protocol-tags.js'
_NAMESPACE_RE = re.compile(r"SHINE_PROTOCOL_NAMESPACE\s*=\s*['\"]([^'\"]+)['\"]")
def _read_namespace() -> str:
source = _UI_PROTOCOL_TAGS.read_text(encoding='utf-8')
match = _NAMESPACE_RE.search(source)
if not match:
raise RuntimeError(f'Не найден SHINE_PROTOCOL_NAMESPACE в {_UI_PROTOCOL_TAGS}')
value = match.group(1).strip()
if not value:
raise RuntimeError('SHiNE protocol namespace пуст')
return value
NAMESPACE = _read_namespace()
APP_TAG_NAME = 'App'
APP_TAG_VALUE = NAMESPACE
CHANNEL_TAG_NAME = 'c'
TYPE_TAG_NAME = 't'
+17 -4
View File
@@ -1,11 +1,24 @@
#!/usr/bin/env python3
import argparse, asyncio, base64, hashlib, json, os, random, struct, sys, time, uuid
from pathlib import Path
import re
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from websockets.asyncio.client import connect
ZERO32 = bytes(32)
FRAME_CODE_V1=1; TEXT_TYPE=1; TEXT_POST=10; VERSION=1
def shine_protocol_namespace():
here = Path(__file__).resolve()
for parent in here.parents:
cfg = parent / 'shine-UI' / 'js' / 'services' / 'protocol-tags.js'
if cfg.exists():
m = re.search(r"SHINE_PROTOCOL_NAMESPACE\s*=\s*['\"]([^'\"]+)['\"]", cfg.read_text(encoding='utf-8'))
if m:
return m.group(1)
raise RuntimeError('Не найден shine-UI/js/services/protocol-tags.js с SHINE_PROTOCOL_NAMESPACE')
SHINE_PROTOCOL_NAMESPACE = shine_protocol_namespace()
def atomic_json(path, obj):
path=Path(path); path.parent.mkdir(parents=True, exist_ok=True)
@@ -54,9 +67,9 @@ def post_body(line_code, prev_line_num, prev_line_hash, this_line_num, text):
if len(tb)>65535: raise ValueError('post text too long')
return struct.pack('>ii32siH',line_code,prev_line_num,prev_line_hash,this_line_num,len(tb))+tb
def frame(prev_hash, block_num, body, ts=None):
ts=int(time.time()) if ts is None else int(ts); size=56+len(body)
return struct.pack('>H32siiqHHH',FRAME_CODE_V1,prev_hash,size,block_num,ts,TEXT_TYPE,TEXT_POST,VERSION)+body
def frame(prev_hash, back32_hash, block_num, body, ts=None):
ts=int(time.time()) if ts is None else int(ts); size=88+len(body)
return struct.pack('>H32s32siiqHHH',FRAME_CODE_V1,prev_hash,back32_hash,size,block_num,ts,TEXT_TYPE,TEXT_POST,VERSION)+body
def h32(b): return hashlib.sha256(b).digest()
def hx(b): return b.hex()
@@ -139,7 +152,7 @@ async def publish_one(cfg,st,items):
else: print('Queue exhausted. Nothing to publish.'); return False
text=items[idx]['text'].strip(); block_num=int(st['last_block_number'])+1; prev_hash=bytes.fromhex(st['last_block_hash']); this_line=int(st['last_line_number'])+1
body=post_body(int(cfg['channel_root_block_number']),int(st['last_line_number']),bytes.fromhex(st['last_line_hash']),this_line,text)
fr=frame(prev_hash,block_num,body); block_hash=h32(fr); tags=[('App','test5590'),('c',cfg['channel_name'].strip().lower())]
back32_hash=ZERO32 if block_num<32 else bytes.fromhex((await block(cfg,block_num-32))[0]); fr=frame(prev_hash,back32_hash,block_num,body); block_hash=h32(fr); tags=[('App',SHINE_PROTOCOL_NAMESPACE),('c',cfg['channel_name'].strip().lower())]
raw=data_item(read_key(cfg['key_file']),tags,fr)
nextidx=idx+1
p={'queue_index':idx,'next_index_after':nextidx,'block_number':block_num,'block_hash':hx(block_hash),'previous_block_number':st['last_block_number'],'previous_block_hash':st['last_block_hash'],'this_line_number':this_line,'data_item_b64':base64.b64encode(raw).decode()}
+17 -4
View File
@@ -1,11 +1,24 @@
#!/usr/bin/env python3
import argparse, asyncio, base64, hashlib, json, os, random, struct, sys, time, uuid
from pathlib import Path
import re
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from websockets.asyncio.client import connect
ZERO32 = bytes(32)
FRAME_CODE_V1=1; TEXT_TYPE=1; TEXT_POST=10; VERSION=1
def shine_protocol_namespace():
here = Path(__file__).resolve()
for parent in here.parents:
cfg = parent / 'shine-UI' / 'js' / 'services' / 'protocol-tags.js'
if cfg.exists():
m = re.search(r"SHINE_PROTOCOL_NAMESPACE\s*=\s*['\"]([^'\"]+)['\"]", cfg.read_text(encoding='utf-8'))
if m:
return m.group(1)
raise RuntimeError('Не найден shine-UI/js/services/protocol-tags.js с SHINE_PROTOCOL_NAMESPACE')
SHINE_PROTOCOL_NAMESPACE = shine_protocol_namespace()
def atomic_json(path, obj):
path=Path(path); path.parent.mkdir(parents=True, exist_ok=True)
@@ -54,9 +67,9 @@ def post_body(line_code, prev_line_num, prev_line_hash, this_line_num, text):
if len(tb)>65535: raise ValueError('post text too long')
return struct.pack('>ii32siH',line_code,prev_line_num,prev_line_hash,this_line_num,len(tb))+tb
def frame(prev_hash, block_num, body, ts=None):
ts=int(time.time()) if ts is None else int(ts); size=56+len(body)
return struct.pack('>H32siiqHHH',FRAME_CODE_V1,prev_hash,size,block_num,ts,TEXT_TYPE,TEXT_POST,VERSION)+body
def frame(prev_hash, back32_hash, block_num, body, ts=None):
ts=int(time.time()) if ts is None else int(ts); size=88+len(body)
return struct.pack('>H32s32siiqHHH',FRAME_CODE_V1,prev_hash,back32_hash,size,block_num,ts,TEXT_TYPE,TEXT_POST,VERSION)+body
def h32(b): return hashlib.sha256(b).digest()
def hx(b): return b.hex()
@@ -139,7 +152,7 @@ async def publish_one(cfg,st,items):
else: print('Queue exhausted. Nothing to publish.'); return False
text=items[idx]['text'].strip(); block_num=int(st['last_block_number'])+1; prev_hash=bytes.fromhex(st['last_block_hash']); this_line=int(st['last_line_number'])+1
body=post_body(int(cfg['channel_root_block_number']),int(st['last_line_number']),bytes.fromhex(st['last_line_hash']),this_line,text)
fr=frame(prev_hash,block_num,body); block_hash=h32(fr); tags=[('App','test5590'),('c',cfg['channel_name'].strip().lower())]
back32_hash=ZERO32 if block_num<32 else bytes.fromhex((await block(cfg,block_num-32))[0]); fr=frame(prev_hash,back32_hash,block_num,body); block_hash=h32(fr); tags=[('App',SHINE_PROTOCOL_NAMESPACE),('c',cfg['channel_name'].strip().lower())]
raw=data_item(read_key(cfg['key_file']),tags,fr)
nextidx=idx+1
p={'queue_index':idx,'next_index_after':nextidx,'block_number':block_num,'block_hash':hx(block_hash),'previous_block_number':st['last_block_number'],'previous_block_hash':st['last_block_hash'],'this_line_number':this_line,'data_item_b64':base64.b64encode(raw).decode()}
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import argparse, asyncio, base64, hashlib, json, os, random, struct, sys, time, uuid
from pathlib import Path
import re
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
@@ -8,6 +9,18 @@ from websockets.asyncio.client import connect
ZERO32 = bytes(32)
FRAME_CODE_V1=1; TEXT_TYPE=1; TEXT_POST=10; VERSION=1
def shine_protocol_namespace():
here = Path(__file__).resolve()
for parent in here.parents:
cfg = parent / 'shine-UI' / 'js' / 'services' / 'protocol-tags.js'
if cfg.exists():
m = re.search(r"SHINE_PROTOCOL_NAMESPACE\s*=\s*['\"]([^'\"]+)['\"]", cfg.read_text(encoding='utf-8'))
if m:
return m.group(1)
raise RuntimeError('Не найден shine-UI/js/services/protocol-tags.js с SHINE_PROTOCOL_NAMESPACE')
SHINE_PROTOCOL_NAMESPACE = shine_protocol_namespace()
def atomic_json(path, obj):
path=Path(path); path.parent.mkdir(parents=True, exist_ok=True)
@@ -56,9 +69,9 @@ def post_body(line_code, prev_line_num, prev_line_hash, this_line_num, text):
if len(tb)>65535: raise ValueError('post text too long')
return struct.pack('>ii32siH',line_code,prev_line_num,prev_line_hash,this_line_num,len(tb))+tb
def frame(prev_hash, block_num, body, ts=None):
ts=int(time.time()) if ts is None else int(ts); size=56+len(body)
return struct.pack('>H32siiqHHH',FRAME_CODE_V1,prev_hash,size,block_num,ts,TEXT_TYPE,TEXT_POST,VERSION)+body
def frame(prev_hash, back32_hash, block_num, body, ts=None):
ts=int(time.time()) if ts is None else int(ts); size=88+len(body)
return struct.pack('>H32s32siiqHHH',FRAME_CODE_V1,prev_hash,back32_hash,size,block_num,ts,TEXT_TYPE,TEXT_POST,VERSION)+body
def h32(b): return hashlib.sha256(b).digest()
def hx(b): return b.hex()
@@ -141,7 +154,7 @@ async def publish_one(cfg,st,items):
else: print('Queue exhausted. Nothing to publish.'); return False
text=items[idx]['text'].strip(); block_num=int(st['last_block_number'])+1; prev_hash=bytes.fromhex(st['last_block_hash']); this_line=int(st['last_line_number'])+1
body=post_body(int(cfg['channel_root_block_number']),int(st['last_line_number']),bytes.fromhex(st['last_line_hash']),this_line,text)
fr=frame(prev_hash,block_num,body); block_hash=h32(fr); tags=[('App','test5590'),('c',cfg['channel_name'].strip().lower())]
back32_hash=ZERO32 if block_num<32 else bytes.fromhex((await block(cfg,block_num-32))[0]); fr=frame(prev_hash,back32_hash,block_num,body); block_hash=h32(fr); tags=[('App',SHINE_PROTOCOL_NAMESPACE),('c',cfg['channel_name'].strip().lower())]
raw=data_item(read_key(cfg['key_file']),tags,fr)
nextidx=idx+1
p={'queue_index':idx,'next_index_after':nextidx,'block_number':block_num,'block_hash':hx(block_hash),'previous_block_number':st['last_block_number'],'previous_block_hash':st['last_block_hash'],'this_line_number':this_line,'data_item_b64':base64.b64encode(raw).decode()}
@@ -236,7 +249,7 @@ async def publish_channel(cfg,st,ch,force=False):
prev_line_block=int(cs.get('last_line_block_number', ch['channel_root_block_number']))
body=post_body(int(ch['channel_root_block_number']),prev_line_block,bytes.fromhex(cs['last_line_hash']),this_line,text)
fr=frame(prev_hash,block_num,body); block_hash=h32(fr)
tags=[('App','test5590'),('c',ch['channel_name'].strip().lower())]
tags=[('App',SHINE_PROTOCOL_NAMESPACE),('c',ch['channel_name'].strip().lower())]
raw=data_item(read_key(cfg['key_file']),tags,fr)
p={'channel_name':ch['channel_name'],'queue_index':idx,'next_index_after':idx+1,'block_number':block_num,
'block_hash':hx(block_hash),'previous_block_number':st['last_block_number'],'previous_block_hash':st['last_block_hash'],