Skip to content

Commit

Permalink
chore: cachePermanentRootStruct for Profile and naming refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
twoeths committed Sep 27, 2024
1 parent 6ae3bc1 commit c6bd7e3
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 42 deletions.
38 changes: 23 additions & 15 deletions packages/ssz/src/type/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@ import {
zeroHash,
zeroNode,
} from "@chainsafe/persistent-merkle-tree";
import {maxChunksToDepth} from "../util/merkleize";
import {ValueWithCachedPermanentRoot, maxChunksToDepth, symbolCachedPermanentRoot} from "../util/merkleize";
import {Require} from "../util/types";
import {namedClass} from "../util/named";
import {Type, ValueOf} from "./abstract";
import {CompositeType, ByteViews, CompositeTypeAny} from "./composite";
import {
getContainerTreeViewClass,
getProfileTreeViewClass,
ValueOfFields,
FieldEntry,
ContainerTreeViewType,
ContainerTreeViewTypeConstructor,
computeSerdesData,
} from "../view/profile";
import {
getContainerTreeViewDUClass,
getProfileTreeViewDUClass,
ContainerTreeViewDUType,
ContainerTreeViewDUTypeConstructor,
} from "../viewDU/profile";
Expand All @@ -42,8 +42,8 @@ export type ProfileOptions<Fields extends Record<string, unknown>> = {
jsonCase?: KeyCase;
casingMap?: CasingMap<Fields>;
cachePermanentRootStruct?: boolean;
getContainerTreeViewClass?: typeof getContainerTreeViewClass;
getContainerTreeViewDUClass?: typeof getContainerTreeViewDUClass;
getProfileTreeViewClass?: typeof getProfileTreeViewClass;
getProfileTreeViewDUClass?: typeof getProfileTreeViewDUClass;
};

export type KeyCase =
Expand Down Expand Up @@ -89,7 +89,7 @@ export class ProfileType<Fields extends Record<string, Type<unknown>>> extends C
private optionalFieldsCount: number;

constructor(readonly fields: Fields, activeFields: BitArray, readonly opts?: ProfileOptions<Fields>) {
super(opts?.cachePermanentRootStruct);
super();

// Render detailed typeName. Consumers should overwrite since it can get long
this.typeName = opts?.typeName ?? renderContainerTypeName(fields);
Expand Down Expand Up @@ -152,8 +152,8 @@ export class ProfileType<Fields extends Record<string, Type<unknown>>> extends C

// TODO: This options are necessary for ContainerNodeStruct to override this.
// Refactor this constructor to allow customization without pollutin the options
this.TreeView = opts?.getContainerTreeViewClass?.(this) ?? getContainerTreeViewClass(this);
this.TreeViewDU = opts?.getContainerTreeViewDUClass?.(this) ?? getContainerTreeViewDUClass(this);
this.TreeView = opts?.getProfileTreeViewClass?.(this) ?? getProfileTreeViewClass(this);
this.TreeViewDU = opts?.getProfileTreeViewDUClass?.(this) ?? getProfileTreeViewDUClass(this);
}

static named<Fields extends Record<string, Type<unknown>>>(
Expand Down Expand Up @@ -361,11 +361,22 @@ export class ProfileType<Fields extends Record<string, Type<unknown>>> extends C
}

// Merkleization

hashTreeRoot(value: ValueOfFields<Fields>): Uint8Array {
// TODO: handle cachePermanentRootStruct
const root = super.hashTreeRoot(value);
return mixInActiveFields(root, this.activeFields);
// Return cached mutable root if any
if (this.cachePermanentRootStruct) {
const cachedRoot = (value as ValueWithCachedPermanentRoot)[symbolCachedPermanentRoot];
if (cachedRoot) {
return cachedRoot;
}
}

const root = mixInActiveFields(super.hashTreeRoot(value), this.activeFields);

if (this.cachePermanentRootStruct) {
(value as ValueWithCachedPermanentRoot)[symbolCachedPermanentRoot] = root;
}

return root;
}

protected getRoots(struct: ValueOfFields<Fields>): Uint8Array[] {
Expand All @@ -385,9 +396,6 @@ export class ProfileType<Fields extends Record<string, Type<unknown>>> extends C

// Proofs

// getPropertyGindex
// getPropertyType
// tree_getLeafGindices
/** INTERNAL METHOD: For view's API, create proof from a tree */

getPropertyGindex(prop: string): Gindex | null {
Expand Down
7 changes: 1 addition & 6 deletions packages/ssz/src/type/stableContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ export class StableContainerType<Fields extends Record<string, Type<unknown>>> e
private padActiveFields: boolean[];

constructor(fields: Fields, readonly maxFields: number, readonly opts?: StableContainerOptions<Fields>) {
// TODO: should pass this to parent?? unit test to confirm
super(opts?.cachePermanentRootStruct);
super();

this.fields = fields;

Expand Down Expand Up @@ -383,10 +382,6 @@ export class StableContainerType<Fields extends Record<string, Type<unknown>>> e

// Proofs

// getPropertyGindex
// getPropertyType
// tree_getLeafGindices

getPropertyGindex(prop: string): Gindex | null {
const gindex = this.fieldsGindex[prop] ?? this.fieldsGindex[this.jsonKeyToFieldName[prop]];
if (gindex === undefined) throw Error(`Unknown container property ${prop}`);
Expand Down
22 changes: 11 additions & 11 deletions packages/ssz/src/view/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export type ContainerTreeViewTypeConstructor<Fields extends Record<string, Type<
* iterate the entire data structure and views
*
*/
class ContainerTreeView<Fields extends Record<string, Type<unknown>>> extends TreeView<ContainerTypeGeneric<Fields>> {
class ProfileTreeView<Fields extends Record<string, Type<unknown>>> extends TreeView<ContainerTypeGeneric<Fields>> {
constructor(readonly type: ContainerTypeGeneric<Fields>, readonly tree: Tree) {
super();
}
Expand All @@ -78,10 +78,10 @@ class ContainerTreeView<Fields extends Record<string, Type<unknown>>> extends Tr
}
}

export function getContainerTreeViewClass<Fields extends Record<string, Type<unknown>>>(
export function getProfileTreeViewClass<Fields extends Record<string, Type<unknown>>>(
type: ContainerTypeGeneric<Fields>
): ContainerTreeViewTypeConstructor<Fields> {
class CustomContainerTreeView extends ContainerTreeView<Fields> {}
class CustomProfileTreeView extends ProfileTreeView<Fields> {}

// Dynamically define prototype methods
for (let index = 0; index < type.fieldsEntries.length; index++) {
Expand All @@ -91,12 +91,12 @@ export function getContainerTreeViewClass<Fields extends Record<string, Type<unk
// The view must use the tree_getFromNode() and tree_setToNode() methods to persist the struct data to the node,
// and use the cached views array to store the new node.
if (isBasicType(fieldType)) {
Object.defineProperty(CustomContainerTreeView.prototype, fieldName, {
Object.defineProperty(CustomProfileTreeView.prototype, fieldName, {
configurable: false,
enumerable: true,

// TODO: Review the memory cost of this closures
get: function (this: CustomContainerTreeView) {
get: function (this: CustomProfileTreeView) {
const leafNode = getNodeAtDepth(this.node, this.type.depth, chunkIndex) as LeafNode;
if (optional && leafNode === zeroNode(0)) {
return null;
Expand All @@ -105,7 +105,7 @@ export function getContainerTreeViewClass<Fields extends Record<string, Type<unk
return fieldType.tree_getFromNode(leafNode);
},

set: function (this: CustomContainerTreeView, value) {
set: function (this: CustomProfileTreeView, value) {
if (optional && value == null) {
const leafNode = zeroNode(0);
this.tree.setNodeAtDepth(this.type.depth, chunkIndex, leafNode);
Expand All @@ -124,12 +124,12 @@ export function getContainerTreeViewClass<Fields extends Record<string, Type<unk
// cache the view itself to retain the caches of the child view. To set a value the view must return a node to
// set it to the parent tree in the field gindex.
else if (isCompositeType(fieldType)) {
Object.defineProperty(CustomContainerTreeView.prototype, fieldName, {
Object.defineProperty(CustomProfileTreeView.prototype, fieldName, {
configurable: false,
enumerable: true,

// Returns TreeView of fieldName
get: function (this: CustomContainerTreeView) {
get: function (this: CustomProfileTreeView) {
const gindex = toGindexBitstring(this.type.depth, chunkIndex);
const tree = this.tree.getSubtree(gindex);
if (optional && tree.rootNode === zeroNode(0)) {
Expand All @@ -140,7 +140,7 @@ export function getContainerTreeViewClass<Fields extends Record<string, Type<unk
},

// Expects TreeView of fieldName
set: function (this: CustomContainerTreeView, value: unknown) {
set: function (this: CustomProfileTreeView, value: unknown) {
if (optional && value == null) {
this.tree.setNodeAtDepth(this.type.depth, chunkIndex, zeroNode(0));
}
Expand All @@ -159,9 +159,9 @@ export function getContainerTreeViewClass<Fields extends Record<string, Type<unk
}

// Change class name
Object.defineProperty(CustomContainerTreeView, "name", {value: type.typeName, writable: false});
Object.defineProperty(CustomProfileTreeView, "name", {value: type.typeName, writable: false});

return CustomContainerTreeView as unknown as ContainerTreeViewTypeConstructor<Fields>;
return CustomProfileTreeView as unknown as ContainerTreeViewTypeConstructor<Fields>;
}

// TODO: deduplicate
Expand Down
20 changes: 10 additions & 10 deletions packages/ssz/src/viewDU/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ class ProfileTreeViewDU<Fields extends Record<string, Type<unknown>>> extends Ba
}
}

export function getContainerTreeViewDUClass<Fields extends Record<string, Type<unknown>>>(
export function getProfileTreeViewDUClass<Fields extends Record<string, Type<unknown>>>(
type: ContainerTypeGeneric<Fields>
): ContainerTreeViewDUTypeConstructor<Fields> {
class CustomContainerTreeViewDU extends ProfileTreeViewDU<Fields> {}
class CustomProfileTreeViewDU extends ProfileTreeViewDU<Fields> {}

// Dynamically define prototype methods
for (let index = 0; index < type.fieldsEntries.length; index++) {
Expand All @@ -135,12 +135,12 @@ export function getContainerTreeViewDUClass<Fields extends Record<string, Type<u
// The view must use the tree_getFromNode() and tree_setToNode() methods to persist the struct data to the node,
// and use the cached views array to store the new node.
if (isBasicType(fieldType)) {
Object.defineProperty(CustomContainerTreeViewDU.prototype, fieldName, {
Object.defineProperty(CustomProfileTreeViewDU.prototype, fieldName, {
configurable: false,
enumerable: true,

// TODO: Review the memory cost of this closures
get: function (this: CustomContainerTreeViewDU) {
get: function (this: CustomProfileTreeViewDU) {
// First walk through the tree to get the root node for that index
let node = this.nodes[index];
if (node === undefined) {
Expand All @@ -155,7 +155,7 @@ export function getContainerTreeViewDUClass<Fields extends Record<string, Type<u
return fieldType.tree_getFromNode(node as LeafNode) as unknown;
},

set: function (this: CustomContainerTreeViewDU, value) {
set: function (this: CustomProfileTreeViewDU, value) {
if (optional && value == null) {
this.nodes[index] = zeroNode(0);
this.nodesChanged.add(index);
Expand Down Expand Up @@ -186,12 +186,12 @@ export function getContainerTreeViewDUClass<Fields extends Record<string, Type<u
// cache the view itself to retain the caches of the child view. To set a value the view must return a node to
// set it to the parent tree in the field gindex.
else if (isCompositeType(fieldType)) {
Object.defineProperty(CustomContainerTreeViewDU.prototype, fieldName, {
Object.defineProperty(CustomProfileTreeViewDU.prototype, fieldName, {
configurable: false,
enumerable: true,

// Returns TreeViewDU of fieldName
get: function (this: CustomContainerTreeViewDU) {
get: function (this: CustomProfileTreeViewDU) {
const viewChanged = this.viewsChanged.get(index);
if (viewChanged) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
Expand Down Expand Up @@ -222,7 +222,7 @@ export function getContainerTreeViewDUClass<Fields extends Record<string, Type<u
},

// Expects TreeViewDU of fieldName
set: function (this: CustomContainerTreeViewDU, view: unknown) {
set: function (this: CustomProfileTreeViewDU, view: unknown) {
if (optional && view == null) {
this.nodes[index] = zeroNode(0);
this.nodesChanged.add(index);
Expand All @@ -246,7 +246,7 @@ export function getContainerTreeViewDUClass<Fields extends Record<string, Type<u
}

// Change class name
Object.defineProperty(CustomContainerTreeViewDU, "name", {value: type.typeName, writable: false});
Object.defineProperty(CustomProfileTreeViewDU, "name", {value: type.typeName, writable: false});

return CustomContainerTreeViewDU as unknown as ContainerTreeViewDUTypeConstructor<Fields>;
return CustomProfileTreeViewDU as unknown as ContainerTreeViewDUTypeConstructor<Fields>;
}

0 comments on commit c6bd7e3

Please sign in to comment.