@chainsafe/ssz
Version:
Simple Serialize
128 lines • 4.77 kB
JavaScript
import { concatGindices, getHashComputations, toGindex, } from "@chainsafe/persistent-merkle-tree";
import { byteArrayEquals, fromHexString, slice, toHexString } from "../util/byteArray.js";
import { CompositeType, LENGTH_GINDEX } from "./composite.js";
/**
* ByteArray: ordered array collection of byte values
* - Value: `Uint8Array`
* - View: `Uint8Array`
* - ViewDU: `Uint8Array`
*
* ByteArray is an immutable value which is represented by a Uint8Array for memory efficiency and performance.
* Note: Consumers of this type MUST never mutate the `Uint8Array` representation of a ByteArray.
*/
export class ByteArrayType extends CompositeType {
isViewMutable = false;
defaultValue() {
// Since it's a byte array the minSize is bytes is the default size
return new Uint8Array(this.minSize);
}
getView(tree) {
return this.getViewDU(tree.rootNode);
}
getViewDU(node) {
return this.tree_toValue(node);
}
commitView(view) {
return this.commitViewDU(view);
}
// there is no respective ViewDU for this type
commitViewDU(view, hcOffset = 0, hcByLevel = null) {
const uint8Array = new Uint8Array(this.value_serializedSize(view));
const dataView = new DataView(uint8Array.buffer, uint8Array.byteOffset, uint8Array.byteLength);
this.value_serializeToBytes({ uint8Array, dataView }, 0, view);
const node = this.tree_deserializeFromBytes({ uint8Array, dataView }, 0, uint8Array.length);
if (hcByLevel !== null && node.h0 === null) {
getHashComputations(node, hcOffset, hcByLevel);
}
return node;
}
cacheOfViewDU() {
return;
}
// Over-write to prevent serialize + deserialize
toView(value) {
return value;
}
toViewDU(value) {
return value;
}
// Serialization + deserialization (only value is generic)
value_serializeToBytes(output, offset, value) {
output.uint8Array.set(value, offset);
return offset + value.length;
}
value_deserializeFromBytes(data, start, end, reuseBytes) {
this.assertValidSize(end - start);
return slice(data.uint8Array, start, end, reuseBytes);
}
value_toTree(value) {
// this saves 1 allocation of Uint8Array
const dataView = new DataView(value.buffer, value.byteOffset, value.byteLength);
return this.tree_deserializeFromBytes({ uint8Array: value, dataView }, 0, value.length);
}
// Merkleization
getBlocksBytes(value) {
// reallocate this.blocksBuffer if needed
if (value.length > this.blocksBuffer.length) {
const chunkCount = Math.ceil(value.length / 32);
this.blocksBuffer = new Uint8Array(Math.ceil(chunkCount / 2) * 64);
}
return getBlocksBytes(value, this.blocksBuffer);
}
// Proofs
getPropertyGindex() {
// Stop navigating below this type. Must only request complete data
return null;
}
getPropertyType() {
throw Error("Must only request ByteArray complete data");
}
getIndexProperty() {
throw Error("Must only request ByteArray complete data");
}
tree_fromProofNode(node) {
return { node, done: true };
}
tree_getLeafGindices(rootGindex, rootNode) {
const byteLen = this.tree_getByteLen(rootNode);
const chunkCount = Math.ceil(byteLen / 32);
const startIndex = concatGindices([rootGindex, toGindex(this.depth, BigInt(0))]);
const gindices = new Array(chunkCount);
for (let i = 0, gindex = startIndex; i < chunkCount; i++, gindex++) {
gindices[i] = gindex;
}
// include the length chunk
if (this.isList) {
gindices.push(concatGindices([rootGindex, LENGTH_GINDEX]));
}
return gindices;
}
// JSON
fromJson(json) {
const value = fromHexString(json);
this.assertValidSize(value.length);
return value;
}
toJson(value) {
return toHexString(value);
}
// ByteArray is immutable
clone(value) {
return value;
}
equals(a, b) {
return byteArrayEquals(a, b);
}
}
export function getBlocksBytes(value, blocksBuffer) {
if (value.length > blocksBuffer.length) {
throw new Error(`data length ${value.length} exceeds blocksBuffer length ${blocksBuffer.length}`);
}
blocksBuffer.set(value);
const valueLen = value.length;
const blockByteLen = Math.ceil(valueLen / 64) * 64;
// all padding bytes must be zero, this is similar to set zeroHash(0)
blocksBuffer.subarray(valueLen, blockByteLen).fill(0);
return blocksBuffer.subarray(0, blockByteLen);
}
//# sourceMappingURL=byteArray.js.map