SHA256
Добавить линии связей и параметров пользователя
This commit is contained in:
@@ -37,12 +37,30 @@ function readFrameTimestampMs(frame) {
|
||||
const seconds = new DataView(frame.buffer, frame.byteOffset, frame.byteLength).getBigInt64(42, false);
|
||||
return Number(seconds * 1000n);
|
||||
}
|
||||
function makeForkBody({ oldBlockchainKeyB64, forkPointBlock, forkPointHash, forkPointTimestampMs, parentTipBlock, parentTipHash, parentTipTimestampMs, reasonCode, comment }) {
|
||||
function readFrameType(frame) {
|
||||
if (!(frame instanceof Uint8Array) || frame.length < 56) throw new Error('Некорректный SHiNE Frame');
|
||||
const view=new DataView(frame.buffer,frame.byteOffset,frame.byteLength);
|
||||
return { type:view.getUint16(50,false), subType:view.getUint16(52,false) };
|
||||
}
|
||||
function readExplicitLinePrefix(frame) {
|
||||
if (!(frame instanceof Uint8Array) || frame.length < 100) throw new Error('Некорректный line Frame');
|
||||
const view=new DataView(frame.buffer,frame.byteOffset,frame.byteLength);
|
||||
return {
|
||||
lineCode:view.getInt32(56,false),
|
||||
prevLineNumber:view.getInt32(60,false),
|
||||
prevLineHash:bytesToHex(frame.slice(64,96)),
|
||||
lineSequence:view.getInt32(96,false),
|
||||
};
|
||||
}
|
||||
function makeForkBody({ lineCode=0, prevLineNumber, prevLineHash, lineSequence, oldBlockchainKeyB64, forkPointBlock, forkPointHash, forkPointTimestampMs, parentTipBlock, parentTipHash, parentTipTimestampMs, reasonCode, comment }) {
|
||||
const oldKey=base64ToBytes(oldBlockchainKeyB64); if(oldKey.length!==32) throw new Error('Некорректный старый blockchain key');
|
||||
const c=TE.encode(normalizeComment(comment)); if(c.length>1024) throw new Error('Комментарий больше 1024 UTF-8 байт');
|
||||
const discarded=Number(parentTipBlock)-Number(forkPointBlock);
|
||||
if(discarded<0) throw new Error('Некорректная точка fork');
|
||||
return concat(oldKey,be32(forkPointBlock),hexToBytes(forkPointHash),be64(forkPointTimestampMs),be32(parentTipBlock),hexToBytes(parentTipHash),be64(parentTipTimestampMs),be32(discarded),Uint8Array.of(Number(reasonCode)),be16(c.length),c);
|
||||
if(Number(lineCode)!==0 || !Number.isInteger(Number(prevLineNumber)) || Number(prevLineNumber)<0 || !Number.isInteger(Number(lineSequence)) || Number(lineSequence)<1) {
|
||||
throw new Error('Некорректная TECH line для FORK');
|
||||
}
|
||||
return concat(be32(lineCode),be32(prevLineNumber),hexToBytes(prevLineHash),be32(lineSequence),oldKey,be32(forkPointBlock),hexToBytes(forkPointHash),be64(forkPointTimestampMs),be32(parentTipBlock),hexToBytes(parentTipHash),be64(parentTipTimestampMs),be32(discarded),Uint8Array.of(Number(reasonCode)),be16(c.length),c);
|
||||
}
|
||||
function makeFrame({ prevHash, blockNumber, type, subType, version=1, body, timestampMs=Date.now() }) {
|
||||
const bodyBytes=body || new Uint8Array(0);
|
||||
@@ -75,6 +93,24 @@ export class KeyRotationClient {
|
||||
return assertOk(await this.auth.ws.request('KeyRotationAddBlock', { blockNumber, prevBlockHash, blockBytesB64 }, 30000), 'KeyRotationAddBlock');
|
||||
}
|
||||
|
||||
async #resolveTechLineTail(source, cutoff) {
|
||||
for(let n=Number(cutoff);n>0;n--) {
|
||||
const block=await this.getBlock(source,n);
|
||||
const parsed=parseAns104DataItem(base64ToBytes(block.blockBytesB64));
|
||||
const kind=readFrameType(parsed.data);
|
||||
if(kind.type!==0 || (kind.subType!==1 && kind.subType!==TECH_FORK_SUBTYPE)) continue;
|
||||
const line=readExplicitLinePrefix(parsed.data);
|
||||
if(line.lineCode!==0 || line.lineSequence<1) throw new Error(`Некорректная TECH line в блоке #${n}`);
|
||||
return {
|
||||
prevLineNumber:n,
|
||||
prevLineHash:String(block.blockHash||''),
|
||||
lineSequence:line.lineSequence+1,
|
||||
};
|
||||
}
|
||||
const header=await this.getBlock(source,0);
|
||||
return { prevLineNumber:0, prevLineHash:String(header.blockHash||''), lineSequence:1 };
|
||||
}
|
||||
|
||||
async copyCandidateChain({ rotation, newBundle, onProgress=()=>{} }) {
|
||||
const cutoff=Number(rotation.forkFromBlock); const source=String(rotation.sourceBlockchainName||'');
|
||||
if(!source || !Number.isInteger(cutoff) || cutoff<0) throw new Error('Некорректное состояние ротации');
|
||||
@@ -100,7 +136,12 @@ export class KeyRotationClient {
|
||||
const tipSource=tipBlock===cutoff ? forkSource : await this.getBlock(source,tipBlock);
|
||||
const forkParsed=parseAns104DataItem(base64ToBytes(forkSource.blockBytesB64));
|
||||
const tipParsed=parseAns104DataItem(base64ToBytes(tipSource.blockBytesB64));
|
||||
const techTail=await this.#resolveTechLineTail(source,cutoff);
|
||||
const forkBody=makeForkBody({
|
||||
lineCode:0,
|
||||
prevLineNumber:techTail.prevLineNumber,
|
||||
prevLineHash:techTail.prevLineHash,
|
||||
lineSequence:techTail.lineSequence,
|
||||
oldBlockchainKeyB64:rotation.oldBlockchainKey,
|
||||
forkPointBlock:cutoff,
|
||||
forkPointHash:rotation.forkFromHash,
|
||||
@@ -111,9 +152,9 @@ export class KeyRotationClient {
|
||||
reasonCode:rotation.reasonCode,
|
||||
comment:rotation.comment,
|
||||
});
|
||||
const techTimestampMs=Number(rotation.createdAtMs)||Number(parentTipTimestampMs)+1000;
|
||||
const techTimestampMs=Number(rotation.createdAtMs)||readFrameTimestampMs(tipParsed.data)+1000;
|
||||
const techFrame=makeFrame({ prevHash:rotation.forkFromHash, blockNumber:cutoff+1, type:0, subType:TECH_FORK_SUBTYPE, version:1, body:forkBody, timestampMs:techTimestampMs });
|
||||
const techRaw=await createAns104DataItem({ owner32, privateKey, data:techFrame, tags:[{name:'App',value:'test5590'}] });
|
||||
const techRaw=await createAns104DataItem({ owner32, privateKey, data:techFrame, tags:[{name:'App',value:'test5590'},{name:'t',value:'tech'}] });
|
||||
await this.addCandidate({ blockNumber:cutoff+1, prevBlockHash:rotation.forkFromHash, blockBytesB64:bytesToBase64(techRaw) });
|
||||
onProgress({ phase:'copy', current:total, total });
|
||||
}
|
||||
@@ -160,17 +201,12 @@ export class KeyRotationClient {
|
||||
}
|
||||
const state=await this.notifyPdaRotation(signature);
|
||||
if(storagePwd) {
|
||||
await updateEncryptedUserSecrets(login, storagePwd, (current)=>{
|
||||
const next={
|
||||
...(current||{}),
|
||||
blockchainKey:newBundle.blockchainPair.privatePkcs8B64,
|
||||
clientKey:newBundle.clientPair.privatePkcs8B64,
|
||||
};
|
||||
// Arweave SAWD-v1 привязан к blockchain key: после ротации старый JWK-cache недействителен.
|
||||
delete next.arweaveWallet;
|
||||
delete next.rootKey;
|
||||
return next;
|
||||
});
|
||||
await updateEncryptedUserSecrets(login, storagePwd, (current)=>({
|
||||
...(current||{}),
|
||||
rootKey:newBundle.rootPair.privatePkcs8B64,
|
||||
blockchainKey:newBundle.blockchainPair.privatePkcs8B64,
|
||||
clientKey:newBundle.clientPair.privatePkcs8B64,
|
||||
}));
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user