@aggris2/ssz
Version:
Simple Serialize
190 lines • 6.62 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.UnionType = void 0;
const persistent_merkle_tree_1 = require("@chainsafe/persistent-merkle-tree");
const merkleize_1 = require("../util/merkleize");
const composite_1 = require("./composite");
const arrayBasic_1 = require("./arrayBasic");
const none_1 = require("./none");
const VALUE_GINDEX = BigInt(2);
const SELECTOR_GINDEX = BigInt(3);
/**
* Union: union type containing one of the given subtypes
* - Notation: Union[type_0, type_1, ...], e.g. union[None, uint64, uint32]
*/
class UnionType extends composite_1.CompositeType {
constructor(types) {
super();
this.types = types;
this.depth = 1;
this.maxChunkCount = 1;
this.fixedSize = null;
this.isList = true;
this.isViewMutable = true;
if (types.length >= 128) {
throw Error("Must have less than 128 types");
}
if (types.length === 0) {
throw Error("Must have at least 1 type option");
}
if (types[0] instanceof none_1.NoneType && types.length < 2) {
throw Error("Must have at least 2 type options if the first is None");
}
for (let i = 1; i < types.length; i++) {
if (types[i] instanceof none_1.NoneType) {
throw Error("None may only be the first option");
}
}
this.typeName = `Union[${types.map((t) => t.typeName).join(",")}]`;
const minLens = [];
const maxLens = [];
for (const _type of types) {
minLens.push(_type.minSize);
maxLens.push(_type.maxSize);
}
this.minSize = 1 + Math.min(...minLens);
this.maxSize = 1 + Math.max(...maxLens);
this.maxSelector = this.types.length - 1;
}
defaultValue() {
return {
selector: 0,
value: this.types[0].defaultValue(),
};
}
getView(tree) {
return this.tree_toValue(tree.rootNode);
}
getViewDU(node) {
return this.tree_toValue(node);
}
cacheOfViewDU() {
return;
}
commitView(view) {
return this.value_toTree(view);
}
commitViewDU(view) {
return this.value_toTree(view);
}
value_serializedSize(value) {
return 1 + this.types[value.selector].value_serializedSize(value.value);
}
value_serializeToBytes(output, offset, value) {
output.uint8Array[offset] = value.selector;
return this.types[value.selector].value_serializeToBytes(output, offset + 1, value.value);
}
value_deserializeFromBytes(data, start, end) {
const selector = data.uint8Array[start];
if (selector > this.maxSelector) {
throw Error(`Invalid selector ${selector}`);
}
return {
selector,
value: this.types[selector].value_deserializeFromBytes(data, start + 1, end),
};
}
tree_serializedSize(node) {
const selector = arrayBasic_1.getLengthFromRootNode(node);
const valueNode = node.left;
return 1 + this.types[selector].value_serializedSize(valueNode);
}
tree_serializeToBytes(output, offset, node) {
const selector = arrayBasic_1.getLengthFromRootNode(node);
const valueNode = node.left;
output.uint8Array[offset] = selector;
return this.types[selector].tree_serializeToBytes(output, offset + 1, valueNode);
}
tree_deserializeFromBytes(data, start, end) {
const selector = data.uint8Array[start];
if (selector > this.maxSelector) {
throw Error(`Invalid selector ${selector}`);
}
const valueNode = this.types[selector].tree_deserializeFromBytes(data, start + 1, end);
return arrayBasic_1.addLengthNode(valueNode, selector);
}
// Merkleization
hashTreeRoot(value) {
return merkleize_1.mixInLength(super.hashTreeRoot(value), value.selector);
}
getRoots(value) {
const valueRoot = this.types[value.selector].hashTreeRoot(value.value);
return [valueRoot];
}
// Proofs
getPropertyGindex(prop) {
switch (prop) {
case "value":
return VALUE_GINDEX;
case "selector":
return SELECTOR_GINDEX;
default:
throw new Error(`Invalid Union type property ${prop}`);
}
}
getPropertyType() {
// a Union has multiple types
throw new Error("Not applicable for Union type");
}
getIndexProperty(index) {
if (index === 0)
return "value";
if (index === 1)
return "selector";
throw Error("Union index of out bounds");
}
tree_getLeafGindices(rootGindex, rootNode) {
if (!rootNode) {
throw Error("rootNode required");
}
const gindices = [persistent_merkle_tree_1.concatGindices([rootGindex, SELECTOR_GINDEX])];
const selector = arrayBasic_1.getLengthFromRootNode(rootNode);
const type = this.types[selector];
const extendedFieldGindex = persistent_merkle_tree_1.concatGindices([rootGindex, VALUE_GINDEX]);
if (composite_1.isCompositeType(type)) {
gindices.push(...type.tree_getLeafGindices(extendedFieldGindex, persistent_merkle_tree_1.getNode(rootNode, VALUE_GINDEX)));
}
else {
gindices.push(extendedFieldGindex);
}
return gindices;
}
// JSON
fromJson(json) {
if (typeof json !== "object") {
throw new Error("JSON must be of type object");
}
const union = json;
if (typeof union.selector !== "number") {
throw new Error("Invalid JSON Union selector must be number");
}
const type = this.types[union.selector];
if (!type) {
throw new Error("Invalid JSON Union selector out of range");
}
return {
selector: union.selector,
value: type.toJson(union.value),
};
}
toJson(value) {
return {
selector: value.selector,
value: this.types[value.selector].toJson(value.value),
};
}
clone(value) {
return {
selector: value.selector,
value: this.types[value.selector].clone(value.value),
};
}
equals(a, b) {
if (a.selector !== b.selector) {
return false;
}
return this.types[a.selector].equals(a.value, b.value);
}
}
exports.UnionType = UnionType;
//# sourceMappingURL=union.js.map