diff --git a/packages/ssz/src/viewDU/listBasic.ts b/packages/ssz/src/viewDU/listBasic.ts index 05bcd06c..1cc21bc6 100644 --- a/packages/ssz/src/viewDU/listBasic.ts +++ b/packages/ssz/src/viewDU/listBasic.ts @@ -60,11 +60,14 @@ export class ListBasicTreeViewDU> extends const chunkIndex = Math.floor(index / this.type.itemsPerChunk); const nodePrev = (this.nodes[chunkIndex] ?? getNodeAtDepth(rootNode, this.type.depth, chunkIndex)) as LeafNode; - const nodeChanged = nodePrev.clone(); - // set remaining items in the same chunk to 0 - for (let i = index + 1; i < (chunkIndex + 1) * this.type.itemsPerChunk; i++) { - this.type.elementType.tree_setToPackedNode(nodeChanged, i, 0); + // we can't set remaining items in the same chunk to 0 with tree_setToPackedNode api due to setBitwiseOR in UintNumberType + // instead, we set the same value in nodePrev up until index + const nodeChanged = LeafNode.fromZero(); + for (let i = chunkIndex * this.type.itemsPerChunk; i <= index; i++) { + const prevValue = this.type.elementType.tree_getFromPackedNode(nodePrev, i); + this.type.elementType.tree_setToPackedNode(nodeChanged, i, prevValue); } + const chunksNode = this.type.tree_getChunksNode(this._rootNode); let newChunksNode = setNodesAtDepth(chunksNode, this.type.chunkDepth, [chunkIndex], [nodeChanged]); // also do the treeZeroAfterIndex operation on the chunks tree diff --git a/packages/ssz/test/unit/byType/listBasic/tree.test.ts b/packages/ssz/test/unit/byType/listBasic/tree.test.ts index e6b15672..4d99d795 100644 --- a/packages/ssz/test/unit/byType/listBasic/tree.test.ts +++ b/packages/ssz/test/unit/byType/listBasic/tree.test.ts @@ -212,24 +212,26 @@ describe("ListBasicType drop caches", () => { }); describe("ListBasicType.sliceTo", () => { - // same to BeaconState InactivityScores - it("Slice List at multiple length", () => { - const listType = new ListBasicType(new UintNumberType(8), 100); - const listView = listType.defaultViewDU(); - const listRoots: string[] = []; - const listSerialized: string[] = []; - - for (let i = 0; i < 16; i++) { - listView.push(i); - listSerialized[i] = toHexString(listView.serialize()); - listRoots[i] = toHexString(listView.hashTreeRoot()); - } - - for (let i = 0; i < 16; i++) { - const listSlice = listView.sliceTo(i); - expect(listSlice.length).to.equal(i + 1, `Wrong length at .sliceTo(${i})`); - expect(toHexString(listSlice.serialize())).equals(listSerialized[i], `Wrong serialize at .sliceTo(${i})`); - expect(toHexString(listSlice.hashTreeRoot())).equals(listRoots[i], `Wrong root at .sliceTo(${i})`); - } - }); + // same to BeaconState inactivityScores and previousEpochParticipation + for (const elementType of [new UintNumberType(8), new UintNumberType(1, {setBitwiseOR: true})]) { + it(`Slice list of ${elementType.typeName} at multiple length`, () => { + const listType = new ListBasicType(elementType, 100); + const listView = listType.defaultViewDU(); + const listRoots: string[] = []; + const listSerialized: string[] = []; + + for (let i = 0; i < 16; i++) { + listView.push(i); + listSerialized[i] = toHexString(listView.serialize()); + listRoots[i] = toHexString(listView.hashTreeRoot()); + } + + for (let i = 0; i < 16; i++) { + const listSlice = listView.sliceTo(i); + expect(listSlice.length).to.equal(i + 1, `Wrong length at .sliceTo(${i})`); + expect(toHexString(listSlice.serialize())).equals(listSerialized[i], `Wrong serialize at .sliceTo(${i})`); + expect(toHexString(listSlice.hashTreeRoot())).equals(listRoots[i], `Wrong root at .sliceTo(${i})`); + } + }); + } });