var __awaiter = this && this.__awaiter || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import { bytesAtOffset, bytesEqual, flexBytesAtOffset } from "../utils/bytes.js"; import { bmtHash } from "./bmt.js"; import { recoverAddress, sign } from "./signer.js"; import { keccak256Hash } from "../utils/hash.js"; import { SPAN_SIZE } from "./span.js"; import { serializeBytes } from "./serialize.js"; import { BeeError } from "../utils/error.js"; import { makeContentAddressedChunk, MAX_PAYLOAD_SIZE, MIN_PAYLOAD_SIZE, assertValidChunkData } from "./cac.js"; import { bytesToHex } from "../utils/hex.js"; import * as socAPI from "../modules/soc.js"; import * as chunkAPI from "../modules/chunk.js"; import { assertAddress } from "../utils/type.js"; const IDENTIFIER_SIZE = 32; const SIGNATURE_SIZE = 65; const SOC_IDENTIFIER_OFFSET = 0; const SOC_SIGNATURE_OFFSET = SOC_IDENTIFIER_OFFSET + IDENTIFIER_SIZE; const SOC_SPAN_OFFSET = SOC_SIGNATURE_OFFSET + SIGNATURE_SIZE; const SOC_PAYLOAD_OFFSET = SOC_SPAN_OFFSET + SPAN_SIZE; function recoverChunkOwner(data) { const cacData = data.slice(SOC_SPAN_OFFSET); const chunkAddress = bmtHash(cacData); const signature = bytesAtOffset(data, SOC_SIGNATURE_OFFSET, SIGNATURE_SIZE); const identifier = bytesAtOffset(data, SOC_IDENTIFIER_OFFSET, IDENTIFIER_SIZE); const digest = keccak256Hash(identifier, chunkAddress); const ownerAddress = recoverAddress(signature, digest); return ownerAddress; } /** * Verifies if the data is a valid single owner chunk * * @param data The chunk data * @param address The address of the single owner chunk * * @returns a single owner chunk or throws error */ export function makeSingleOwnerChunkFromData(data, address) { const ownerAddress = recoverChunkOwner(data); const identifier = bytesAtOffset(data, SOC_IDENTIFIER_OFFSET, IDENTIFIER_SIZE); const socAddress = keccak256Hash(identifier, ownerAddress); if (!bytesEqual(address, socAddress)) { throw new BeeError('SOC Data does not match given address!'); } const signature = () => bytesAtOffset(data, SOC_SIGNATURE_OFFSET, SIGNATURE_SIZE); const span = () => bytesAtOffset(data, SOC_SPAN_OFFSET, SPAN_SIZE); const payload = () => flexBytesAtOffset(data, SOC_PAYLOAD_OFFSET, MIN_PAYLOAD_SIZE, MAX_PAYLOAD_SIZE); return { data, identifier: () => identifier, signature, span, payload, address: () => socAddress, owner: () => ownerAddress }; } export function makeSOCAddress(identifier, address) { return keccak256Hash(identifier, address); } /** * Creates a single owner chunk object * * @param chunk A chunk object used for the span and payload * @param identifier The identifier of the chunk * @param signer The singer interface for signing the chunk */ export function makeSingleOwnerChunk(chunk, identifier, signer) { return __awaiter(this, void 0, void 0, function* () { const chunkAddress = chunk.address(); assertValidChunkData(chunk.data, chunkAddress); const digest = keccak256Hash(identifier, chunkAddress); const signature = yield sign(signer, digest); const data = serializeBytes(identifier, signature, chunk.span(), chunk.payload()); const address = makeSOCAddress(identifier, signer.address); return { data, identifier: () => identifier, signature: () => signature, span: () => chunk.span(), payload: () => chunk.payload(), address: () => address, owner: () => signer.address }; }); } /** * Helper function to upload a chunk. * * It uses the Chunk API and calculates the address before uploading. * * @param ky Ky instance * @param chunk A chunk object * @param postageBatchId Postage BatchId that will be assigned to uploaded data * @param options Upload options */ export function uploadSingleOwnerChunk(ky, chunk, postageBatchId, options) { return __awaiter(this, void 0, void 0, function* () { const owner = bytesToHex(chunk.owner()); const identifier = bytesToHex(chunk.identifier()); const signature = bytesToHex(chunk.signature()); const data = serializeBytes(chunk.span(), chunk.payload()); return socAPI.upload(ky, owner, identifier, signature, data, postageBatchId, options); }); } /** * Helper function to create and upload SOC. * * @param ky Ky instance * @param signer The singer interface for signing the chunk * @param postageBatchId * @param identifier The identifier of the chunk * @param data The chunk data * @param options */ export function uploadSingleOwnerChunkData(ky, signer, postageBatchId, identifier, data, options) { return __awaiter(this, void 0, void 0, function* () { assertAddress(postageBatchId); const cac = makeContentAddressedChunk(data); const soc = yield makeSingleOwnerChunk(cac, identifier, signer); return uploadSingleOwnerChunk(ky, soc, postageBatchId, options); }); } /** * Helper function to download SOC. * * @param url The url of the Bee service * @param ownerAddress The singer interface for signing the chunk * @param identifier The identifier of the chunk */ export function downloadSingleOwnerChunk(ky, ownerAddress, identifier) { return __awaiter(this, void 0, void 0, function* () { const address = makeSOCAddress(identifier, ownerAddress); const data = yield chunkAPI.download(ky, bytesToHex(address)); return makeSingleOwnerChunkFromData(data, address); }); }