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
@@ -25,16 +25,16 @@ index.html?key=<BASE58_BLOCKCHAIN_PUBLIC_KEY>&channel=books
&solanaRpc=https://api.mainnet-beta.solana.com
```
`channel` можно не передавать. Тогда viewer ищет все DataItem пользователя с `App=test5590` и строит список каналов из найденных блоков.
`channel` можно не передавать. Тогда viewer ищет все DataItem пользователя с `App=test5591` и строит список каналов из найденных блоков.
## Что делает viewer
1. Если передан `login`, вычисляет PDA `user_login=<login>` программы `SHiNEPr1APdAgNBteUyBXcNovaHctpSjUu8oH2ZJdN6` и читает `blockchainKey`.
2. Если передан `key`, использует его напрямую и не обращается к Solana.
3. Из Ed25519/Solana public key вычисляет Arweave owner address как `base64url(SHA-256(pubkey32))`.
4. Делает Arweave GraphQL запрос по owner + `App=test5590`; `channel` применяется локально после загрузки авторского блокчейна.
4. Делает Arweave GraphQL запрос по owner + `App=test5591`; `channel` применяется локально после загрузки авторского блокчейна.
5. Загружает payload каждого DataItem через gateway `/<DataItemId>`.
6. Разбирает payload как SHiNE Frame v1 (`frameCode=0x0001`, header 56 bytes).
6. Разбирает payload как SHiNE Frame v1 (`frameCode=0x0001`, header 88 bytes).
7. Дедуплицирует повторно опубликованные одинаковые пользовательские блоки по SHA-256 Frame v1.
8. Восстанавливает канал/сообщения тем же body parser, который использовал старый viewer.
+28 -13
View File
@@ -1097,9 +1097,12 @@ var solanaWeb3=function(exports){"use strict";function getDefaultExportFromCjs(x
const BLOCK_TYPE_SESSIONS = 50;
const BLOCK_TYPE_TRUSTED_STATE = 70;
const BLOCK_TYPE_ARCHIVE_HEAD = 80;
const BCH_FRAME_HEADER_SIZE = 56;
const BCH_FRAME_HEADER_SIZE = 88;
const BCH_FRAME_CODE_V1 = 0x0001;
const SHINE_ARWEAVE_APP_TAG = 'test5590';
// Transport namespace актуального standalone Viewer.
const SHINE_PROTOCOL_NAMESPACE = 'test5591';
const SHINE_ARWEAVE_APP_TAG = SHINE_PROTOCOL_NAMESPACE;
const SHINE_ARWEAVE_CHANNEL_TAG = 'c';
const BCH_TYPE_TECH = 0;
const BCH_TYPE_TEXT = 1;
const BCH_SUBTYPE_HEADER = 0;
@@ -2058,22 +2061,23 @@ var solanaWeb3=function(exports){"use strict";function getDefaultExportFromCjs(x
if (frameCode !== BCH_FRAME_CODE_V1) {
throw new Error(`Неожиданный frameCode 0x${frameCode.toString(16)} (ожидался 0x0001)`);
}
const blockSize = readInt32BE(bytes, 34);
const blockSize = readInt32BE(bytes, 66);
if (blockSize !== bytes.length || blockSize < BCH_FRAME_HEADER_SIZE) {
throw new Error(`Frame size mismatch: blockSize=${blockSize}, actual=${bytes.length}`);
}
const hashBytes = await digestSha256(bytes);
const type = readUint16BE(bytes, 50);
const subType = readUint16BE(bytes, 52);
const version = readUint16BE(bytes, 54);
const type = readUint16BE(bytes, 82);
const subType = readUint16BE(bytes, 84);
const version = readUint16BE(bytes, 86);
const bodyBytes = bytes.slice(BCH_FRAME_HEADER_SIZE);
const body = parseBlockchainBody(type, subType, version, bodyBytes);
return {
frameCode,
prevHashHex: bytesToHex(bytes.slice(2, 34)),
back32HashHex: bytesToHex(bytes.slice(34, 66)),
blockSize,
blockNumber: readInt32BE(bytes, 38),
timestampSec: readInt64BE(bytes, 42),
blockNumber: readInt32BE(bytes, 70),
timestampSec: readInt64BE(bytes, 74),
type,
subType,
version,
@@ -2501,7 +2505,7 @@ var solanaWeb3=function(exports){"use strict";function getDefaultExportFromCjs(x
let offset = 0;
while (offset < data.length) {
if (data.length - offset < BCH_FRAME_HEADER_SIZE) throw new Error(`Frame обрывается на смещении ${offset}`);
const blockSize = readInt32BE(data, offset + 34);
const blockSize = readInt32BE(data, offset + 66);
if (blockSize < BCH_FRAME_HEADER_SIZE || offset + blockSize > data.length) throw new Error(`Некорректный blockSize ${blockSize} на смещении ${offset}`);
blocks.push(await parseBlockchainBlock(data.slice(offset, offset + blockSize)));
offset += blockSize;
@@ -3345,7 +3349,7 @@ var solanaWeb3=function(exports){"use strict";function getDefaultExportFromCjs(x
const oldSetContentStatus = setContentStatus;
setContentStatus = function(kind,text){ oldSetContentStatus(kind,text); const el=document.getElementById('v3-status'); if(el) el.textContent=text; v3Log(text); };
function v3Theme(theme){ document.documentElement.dataset.theme=theme; localStorage.setItem('shine.viewer.theme',theme); const b=document.getElementById('v3-theme'); if(b)b.textContent=theme==='dark'?'☀':'☾'; }
function v3RenderBlocks(){ const host=document.getElementById('v3-block-view'); if(!host)return; host.innerHTML=''; const wrap=document.createElement('div'); wrap.className='v3-blocks'; const blocks=(currentBlockchainView?.rawBlocks||V3.blocks||[]).slice().sort((a,b)=>b.blockNumber-a.blockNumber); blocks.forEach(b=>{ const d=document.createElement('details'); d.className='v3-block'; const sm=document.createElement('summary'); sm.textContent=`#${b.blockNumber} · type ${b.type}/${b.subType} · ${formatTimestamp(Number(b.timestampSec)*1000)}`; const pre=document.createElement('pre'); pre.textContent=JSON.stringify({blockNumber:b.blockNumber,type:b.type,subType:b.subType,version:b.version,hash:b.hashHex,prevHash:b.prevHashHex,arweaveId:b.arweaveId,body:b.body},(k,v)=>typeof v==='bigint'?String(v):v,2); d.append(sm,pre); wrap.appendChild(d); }); if(!blocks.length)wrap.textContent='Блоки ещё не загружены.'; host.appendChild(wrap); }
function v3RenderBlocks(){ const host=document.getElementById('v3-block-view'); if(!host)return; host.innerHTML=''; const wrap=document.createElement('div'); wrap.className='v3-blocks'; const blocks=(currentBlockchainView?.rawBlocks||V3.blocks||[]).slice().sort((a,b)=>b.blockNumber-a.blockNumber); blocks.forEach(b=>{ const d=document.createElement('details'); d.className='v3-block'; const sm=document.createElement('summary'); sm.textContent=`#${b.blockNumber} · type ${b.type}/${b.subType} · ${formatTimestamp(Number(b.timestampSec)*1000)}`; const pre=document.createElement('pre'); pre.textContent=JSON.stringify({blockNumber:b.blockNumber,type:b.type,subType:b.subType,version:b.version,hash:b.hashHex,prevHash:b.prevHashHex,back32Hash:b.back32HashHex,arweaveId:b.arweaveId,body:b.body},(k,v)=>typeof v==='bigint'?String(v):v,2); d.append(sm,pre); wrap.appendChild(d); }); if(!blocks.length)wrap.textContent='Блоки ещё не загружены.'; host.appendChild(wrap); }
function v3SetView(mode){ const bv=document.getElementById('v3-block-view'), cb=document.getElementById('content-browser'); document.getElementById('v3-channel-tab').classList.toggle('is-active',mode==='channel'); document.getElementById('v3-blocks-tab').classList.toggle('is-active',mode==='blocks'); if(bv)bv.hidden=mode!=='blocks'; if(cb)cb.hidden=mode==='blocks'; if(mode==='blocks')v3RenderBlocks(); }
async function v3ClearCache(){ try{ const keys=Object.keys(localStorage).filter(k=>k.startsWith('shine.viewer.data.')); keys.forEach(k=>localStorage.removeItem(k)); if('caches' in window){ for(const k of await caches.keys()) if(k.startsWith('shine-viewer-')) await caches.delete(k); } v3Log('Кэш данных очищен'); }catch(e){v3Log('Ошибка очистки кэша: '+e.message);} }
function v3CacheKey(key,channel){return 'shine.viewer.author-chain.'+String(key);}
@@ -3372,7 +3376,7 @@ var solanaWeb3=function(exports){"use strict";function getDefaultExportFromCjs(x
function v3Verification(blocks){
blocks=(blocks||[]).slice().sort((a,b)=>a.blockNumber-b.blockNumber);
const byNum=new Map(blocks.map(b=>[Number(b.blockNumber),b]));
const result={total:blocks.length,frameHash:{ok:blocks.length,bad:0,na:0},global:{ok:0,bad:0,na:0},channel:{ok:0,bad:0,na:0},owner:{ok:0,bad:0,na:0},signature:{ok:0,bad:0,na:blocks.length},issues:[]};
const result={total:blocks.length,frameHash:{ok:blocks.length,bad:0,na:0},global:{ok:0,bad:0,na:0},back32:{ok:0,bad:0,na:0},channel:{ok:0,bad:0,na:0},owner:{ok:0,bad:0,na:0},signature:{ok:0,bad:0,na:blocks.length},issues:[]};
for(const b of blocks){
// hashHex is SHA-256(Frame) calculated locally by parseBlockchainBlock.
if(!b.hashHex){result.frameHash.ok--;result.frameHash.na++;}
@@ -3384,6 +3388,16 @@ var solanaWeb3=function(exports){"use strict";function getDefaultExportFromCjs(x
else if(String(prev.hashHex).toLowerCase()===String(b.prevHashHex).toLowerCase()) result.global.ok++;
else{result.global.bad++;result.issues.push({kind:'global',state:'bad',block:b.blockNumber,text:`prevHash не совпадает с SHA-256 блока #${prev.blockNumber}`});}
}
const back32=String(b.back32HashHex||'');
if(Number(b.blockNumber)<32){
if(v3ZeroHash(back32)) result.back32.ok++;
else{result.back32.bad++;result.issues.push({kind:'back32',state:'bad',block:b.blockNumber,text:'Для блока <32 back32Hash должен быть нулевым'});}
} else {
const target=byNum.get(Number(b.blockNumber)-32);
if(!target){result.back32.na++;result.issues.push({kind:'back32',state:'na',block:b.blockNumber,text:`Нет блока #${Number(b.blockNumber)-32} для проверки back32Hash`});}
else if(String(target.hashHex).toLowerCase()===back32.toLowerCase()) result.back32.ok++;
else{result.back32.bad++;result.issues.push({kind:'back32',state:'bad',block:b.blockNumber,text:`back32Hash не совпадает с SHA-256 блока #${Number(b.blockNumber)-32}`});}
}
const body=b.body||{};
if(body.kind==='text_line' || body.kind==='create_channel'){
const pn=Number(body.prevLineNumber||0), ph=String(body.prevLineHashHex||'');
@@ -3402,8 +3416,8 @@ var solanaWeb3=function(exports){"use strict";function getDefaultExportFromCjs(x
function v3UpdateVerification(){
const r=v3Verification(currentBlockchainView?.rawBlocks||V3.blocks||[]);
V3.verification=r;
const bad=r.global.bad+r.channel.bad+r.frameHash.bad+r.owner.bad+r.signature.bad;
const checked=r.global.ok+r.channel.ok;
const bad=r.global.bad+r.back32.bad+r.channel.bad+r.frameHash.bad+r.owner.bad+r.signature.bad;
const checked=r.global.ok+r.back32.ok+r.channel.ok;
const el=document.getElementById('v3-status');
if(el && r.total) el.textContent=`${bad?'⚠':'✓'} Хэши ${checked} · global ${v3MetricText(r.global)} · канал ${v3MetricText(r.channel)} · owner ${v3MetricText(r.owner)}`;
return r;
@@ -3416,6 +3430,7 @@ var solanaWeb3=function(exports){"use strict";function getDefaultExportFromCjs(x
document.getElementById('v3-verify-summary').innerHTML=
v3VerifyCard('SHA-256 Frame',r.frameHash,'вычислен локально')+
v3VerifyCard('Общая цепочка',r.global,'prevHash')+
v3VerifyCard('Резерв N−32',r.back32,'back32Hash')+
v3VerifyCard('Цепочки каналов',r.channel,'prevLineHash')+
v3VerifyCard('Arweave owner',r.owner,'совпадение выборки owner');
const sig=document.getElementById('v3-signature-note');