diff --git a/packages/ssz/src/view/stableContainer.ts b/packages/ssz/src/view/stableContainer.ts index 8e7f45a8..b5cb6bda 100644 --- a/packages/ssz/src/view/stableContainer.ts +++ b/packages/ssz/src/view/stableContainer.ts @@ -30,7 +30,7 @@ export type NonOptionalFields>> = { }; /** Expected API of this View's type. This interface allows to break a recursive dependency between types and views */ -export type ContainerTypeGeneric>> = CompositeType< +export type StableContainerTypeGeneric>> = CompositeType< ValueOfFields, ContainerTreeViewType, unknown @@ -67,9 +67,9 @@ export type FieldsView>> = { }; export type ContainerTreeViewType>> = FieldsView & - TreeView>; + TreeView>; export type ContainerTreeViewTypeConstructor>> = { - new (type: ContainerTypeGeneric, tree: Tree): ContainerTreeViewType; + new (type: StableContainerTypeGeneric, tree: Tree): ContainerTreeViewType; }; /** @@ -87,8 +87,10 @@ export type ContainerTreeViewTypeConstructor>> extends TreeView> { - constructor(readonly type: ContainerTypeGeneric, readonly tree: Tree) { +class ContainerTreeView>> extends TreeView< + StableContainerTypeGeneric +> { + constructor(readonly type: StableContainerTypeGeneric, readonly tree: Tree) { super(); } @@ -98,7 +100,7 @@ class ContainerTreeView>> extends Tr } export function getContainerTreeViewClass>>( - type: ContainerTypeGeneric + type: StableContainerTypeGeneric ): ContainerTreeViewTypeConstructor { class CustomContainerTreeView extends ContainerTreeView {} diff --git a/packages/ssz/src/viewDU/stableContainer.ts b/packages/ssz/src/viewDU/stableContainer.ts index ae09fcb6..598fabed 100644 --- a/packages/ssz/src/viewDU/stableContainer.ts +++ b/packages/ssz/src/viewDU/stableContainer.ts @@ -1,11 +1,12 @@ -import {getNodeAtDepth, LeafNode, Node, setNodesAtDepth, zeroNode} from "@chainsafe/persistent-merkle-tree"; +import {getNodeAtDepth, LeafNode, Node, zeroNode} from "@chainsafe/persistent-merkle-tree"; import {ByteViews, Type} from "../type/abstract"; import {BasicType, isBasicType} from "../type/basic"; -import {CompositeType, isCompositeType, CompositeTypeAny} from "../type/composite"; -import {computeSerdesData, ContainerTypeGeneric} from "../view/stableContainer"; +import {CompositeType, isCompositeType} from "../type/composite"; +import {computeSerdesData, StableContainerTypeGeneric} from "../view/stableContainer"; import {TreeViewDU} from "./abstract"; import {OptionalType} from "../type/optional"; import {BitArray} from "../value/bitArray"; +import {BasicContainerTreeViewDU} from "./container"; /* eslint-disable @typescript-eslint/member-ordering */ @@ -30,9 +31,9 @@ export type FieldsViewDU>> = { }; export type ContainerTreeViewDUType>> = FieldsViewDU & - TreeViewDU>; + TreeViewDU>; export type ContainerTreeViewDUTypeConstructor>> = { - new (type: ContainerTypeGeneric, node: Node, cache?: unknown): ContainerTreeViewDUType; + new (type: StableContainerTypeGeneric, node: Node, cache?: unknown): ContainerTreeViewDUType; }; type ContainerTreeViewDUCache = { @@ -42,96 +43,27 @@ type ContainerTreeViewDUCache = { nodesPopulated: boolean; }; -class ContainerTreeViewDU>> extends TreeViewDU< - ContainerTypeGeneric -> { +class StableContainerTreeViewDU>> extends BasicContainerTreeViewDU { /** pending active fields bitvector */ protected activeFields: BitArray; - protected nodes: Node[] = []; - protected caches: unknown[]; - protected readonly nodesChanged = new Set(); - protected readonly viewsChanged = new Map(); - private nodesPopulated: boolean; constructor( - readonly type: ContainerTypeGeneric, + readonly type: StableContainerTypeGeneric, protected _rootNode: Node, cache?: ContainerTreeViewDUCache ) { - super(); + super(type, _rootNode, cache); if (cache) { this.activeFields = cache.activeFields; - this.nodes = cache.nodes; - this.caches = cache.caches; - this.nodesPopulated = cache.nodesPopulated; } else { this.activeFields = type.tree_getActiveFields(_rootNode); - this.nodes = []; - this.caches = []; - this.nodesPopulated = false; } } - get node(): Node { - return this._rootNode; - } - get cache(): ContainerTreeViewDUCache { - return { - activeFields: this.activeFields, - nodes: this.nodes, - caches: this.caches, - nodesPopulated: this.nodesPopulated, - }; - } - - commit(): void { - if (this.nodesChanged.size === 0 && this.viewsChanged.size === 0) { - return; - } - - const nodesChanged: {index: number; node: Node}[] = []; - - for (const [index, view] of this.viewsChanged) { - const fieldType = this.type.fieldsEntries[index].fieldType as unknown as CompositeTypeAny; - const node = fieldType.commitViewDU(view); - // Set new node in nodes array to ensure data represented in the tree and fast nodes access is equal - this.nodes[index] = node; - nodesChanged.push({index, node}); - - // Cache the view's caches to preserve it's data after 'this.viewsChanged.clear()' - const cache = fieldType.cacheOfViewDU(view); - if (cache) this.caches[index] = cache; - } - - for (const index of this.nodesChanged) { - nodesChanged.push({index, node: this.nodes[index]}); - } - - // TODO: Optimize to loop only once, Numerical sort ascending - const nodesChangedSorted = nodesChanged.sort((a, b) => a.index - b.index); - const indexes = nodesChangedSorted.map((entry) => entry.index); - const nodes = nodesChangedSorted.map((entry) => entry.node); - - this._rootNode = setNodesAtDepth(this._rootNode, this.type.depth, indexes, nodes); - this._rootNode = this.type.tree_setActiveFields(this._rootNode, this.activeFields); - - this.nodesChanged.clear(); - this.viewsChanged.clear(); - } - - protected clearCache(): void { - this.nodes = []; - this.caches = []; - this.nodesPopulated = false; - - // Must clear nodesChanged, otherwise a subsequent commit call will break, because it assumes a node is there - this.nodesChanged.clear(); - - // It's not necessary to clear this.viewsChanged since they have no effect on the cache. - // However preserving _SOME_ caches results in a very unpredictable experience. - this.viewsChanged.clear(); + const result = super.cache; + return {...result, activeFields: this.activeFields}; } /** @@ -184,9 +116,9 @@ class ContainerTreeViewDU>> extends } export function getContainerTreeViewDUClass>>( - type: ContainerTypeGeneric + type: StableContainerTypeGeneric ): ContainerTreeViewDUTypeConstructor { - class CustomContainerTreeViewDU extends ContainerTreeViewDU {} + class CustomContainerTreeViewDU extends StableContainerTreeViewDU {} // Dynamically define prototype methods for (let index = 0; index < type.fieldsEntries.length; index++) {