Skip to content

Commit

Permalink
fix: only overwrite ListValidatorViewDU
Browse files Browse the repository at this point in the history
  • Loading branch information
twoeths committed Jul 16, 2024
1 parent 93ef142 commit 1465945
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 290 deletions.
60 changes: 53 additions & 7 deletions packages/types/src/phase0/validator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import {ByteViews, ContainerNodeStructType, ValueOfFields} from "@chainsafe/ssz";
import {Node} from "@chainsafe/persistent-merkle-tree";
import * as primitiveSsz from "../primitive/sszTypes.js";
import {ValidatorTreeViewDU} from "./viewDU/validator.js";

const {Boolean, Bytes32, UintNum64, BLSPubkey, EpochInf} = primitiveSsz;

Expand All @@ -15,6 +13,7 @@ const UINT32_SIZE = 4;
const PUBKEY_SIZE = 48;
const WITHDRAWAL_CREDENTIALS_SIZE = 32;
const SLASHED_SIZE = 1;
const CHUNK_SIZE = 32;

export const ValidatorType = {
pubkey: BLSPubkey,
Expand All @@ -35,10 +34,6 @@ export class ValidatorNodeStructType extends ContainerNodeStructType<typeof Vali
super(ValidatorType, {typeName: "Validator", jsonCase: "eth2"});
}

getViewDU(node: Node): ValidatorTreeViewDU {
return new ValidatorTreeViewDU(this, node);
}

value_serializeToBytes(
{uint8Array: output, dataView}: ByteViews,
offset: number,
Expand All @@ -65,6 +60,58 @@ export class ValidatorNodeStructType extends ContainerNodeStructType<typeof Vali
}
}

export const ValidatorNodeStruct = new ValidatorNodeStructType();

/**
* Write to level3 and level4 bytes to compute merkle root. Note that this is to compute
* merkle root and it's different from serialization (which is more compressed).
* pub0 + pub1 are at level4, they will be hashed to 1st chunked of level 3
* then use 8 chunks of level 3 to compute the root hash.
* reserved withdr eff sla actElig act exit with
* level 3 |----------|----------|----------|----------|----------|----------|----------|----------|
*
* pub0 pub1
* level4 |----------|----------|
*
*/
export function validatorToChunkBytes(
level3: ByteViews,
level4: Uint8Array,
value: ValueOfFields<typeof ValidatorType>
): void {
const {
pubkey,
withdrawalCredentials,
effectiveBalance,
slashed,
activationEligibilityEpoch,
activationEpoch,
exitEpoch,
withdrawableEpoch,
} = value;
const {uint8Array: outputLevel3, dataView} = level3;

// pubkey = 48 bytes which is 2 * CHUNK_SIZE
level4.set(pubkey, 0);
let offset = CHUNK_SIZE;
outputLevel3.set(withdrawalCredentials, offset);
offset += CHUNK_SIZE;
// effectiveBalance is UintNum64
dataView.setUint32(offset, effectiveBalance & 0xffffffff, true);
dataView.setUint32(offset + 4, (effectiveBalance / NUMBER_2_POW_32) & 0xffffffff, true);

offset += CHUNK_SIZE;
dataView.setUint32(offset, slashed ? 1 : 0, true);
offset += CHUNK_SIZE;
writeEpochInf(dataView, offset, activationEligibilityEpoch);
offset += CHUNK_SIZE;
writeEpochInf(dataView, offset, activationEpoch);
offset += CHUNK_SIZE;
writeEpochInf(dataView, offset, exitEpoch);
offset += CHUNK_SIZE;
writeEpochInf(dataView, offset, withdrawableEpoch);
}

function writeEpochInf(dataView: DataView, offset: number, value: number): number {
if (value === Infinity) {
dataView.setUint32(offset, 0xffffffff, true);
Expand All @@ -79,4 +126,3 @@ function writeEpochInf(dataView: DataView, offset: number, value: number): numbe
}
return offset;
}
export const ValidatorNodeStruct = new ValidatorNodeStructType();
55 changes: 34 additions & 21 deletions packages/types/src/phase0/viewDU/listValidator.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {ListCompositeType, ArrayCompositeTreeViewDUCache, ListCompositeTreeViewDU, ByteViews} from "@chainsafe/ssz";
import {
HashComputationGroup,
Node,
digestNLevel,
setNodesAtDepth,
} from "@chainsafe/persistent-merkle-tree";
import {ValidatorNodeStructType} from "../validator.js";
import {ValidatorTreeViewDU} from "./validator.js";

ListCompositeType,
ArrayCompositeTreeViewDUCache,
ListCompositeTreeViewDU,
ByteViews,
ContainerNodeStructTreeViewDU,
} from "@chainsafe/ssz";
import {HashComputationGroup, Node, digestNLevel, setNodesAtDepth} from "@chainsafe/persistent-merkle-tree";
import {byteArrayIntoHashObject} from "@chainsafe/as-sha256";
import {ValidatorNodeStructType, ValidatorType, validatorToChunkBytes} from "../validator.js";

/**
* hashtree has a MAX_SIZE of 1024 bytes = 32 chunks
Expand Down Expand Up @@ -61,6 +61,10 @@ export class ListValidatorTreeViewDU extends ListCompositeTreeViewDU<ValidatorNo
}

// TODO - batch: remove this type cast
const viewsChanged = this.viewsChanged as unknown as Map<
number,
ContainerNodeStructTreeViewDU<typeof ValidatorType>
>;
const indicesChanged = Array.from(this.viewsChanged.keys()).sort((a, b) => a - b);
const endBatch = indicesChanged.length - (indicesChanged.length % PARALLEL_FACTOR);
// nodesChanged is sorted by index
Expand All @@ -73,8 +77,10 @@ export class ListValidatorTreeViewDU extends ListCompositeTreeViewDU<ValidatorNo
}
const indexInBatch = i % PARALLEL_FACTOR;
const viewIndex = indicesChanged[i];
const viewChanged = this.viewsChanged.get(viewIndex) as ValidatorTreeViewDU;
viewChanged.valueToChunkBytes(level3ByteViewsArr[indexInBatch], level4BytesArr[indexInBatch]);
const viewChanged = viewsChanged.get(viewIndex);
if (viewChanged) {
validatorToChunkBytes(level3ByteViewsArr[indexInBatch], level4BytesArr[indexInBatch], viewChanged.value);
}

if (indexInBatch === PARALLEL_FACTOR - 1) {
// hash level 4, this is populated to pubkeyRoots
Expand All @@ -88,11 +94,15 @@ export class ListValidatorTreeViewDU extends ListCompositeTreeViewDU<ValidatorNo
for (let j = PARALLEL_FACTOR - 1; j >= 0; j--) {
const viewIndex = indicesChanged[i - j];
const indexInBatch = (i - j) % PARALLEL_FACTOR;
const viewChanged = this.viewsChanged.get(viewIndex) as ValidatorTreeViewDU;
viewChanged.commitToRoot(validatorRoots[indexInBatch]);
nodesChanged.push({index: viewIndex, node: viewChanged.node});
// Set new node in nodes array to ensure data represented in the tree and fast nodes access is equal
this.nodes[viewIndex] = viewChanged.node;
const viewChanged = viewsChanged.get(viewIndex);
if (viewChanged) {
viewChanged.commitNoHash();
const branchNodeStruct = viewChanged.node;
byteArrayIntoHashObject(validatorRoots[indexInBatch], 0, branchNodeStruct);
nodesChanged.push({index: viewIndex, node: viewChanged.node});
// Set new node in nodes array to ensure data represented in the tree and fast nodes access is equal
this.nodes[viewIndex] = viewChanged.node;
}
}
}
}
Expand All @@ -101,11 +111,14 @@ export class ListValidatorTreeViewDU extends ListCompositeTreeViewDU<ValidatorNo
// it's not much different to commit one by one
for (let i = endBatch; i < indicesChanged.length; i++) {
const viewIndex = indicesChanged[i];
const viewChanged = this.viewsChanged.get(viewIndex) as ValidatorTreeViewDU;
viewChanged.commit();
nodesChanged.push({index: viewIndex, node: viewChanged.node});
// Set new node in nodes array to ensure data represented in the tree and fast nodes access is equal
this.nodes[viewIndex] = viewChanged.node;
const viewChanged = viewsChanged.get(viewIndex);
if (viewChanged) {
// commit and hash
viewChanged.commit();
nodesChanged.push({index: viewIndex, node: viewChanged.node});
// Set new node in nodes array to ensure data represented in the tree and fast nodes access is equal
this.nodes[viewIndex] = viewChanged.node;
}
}

// do the remaining commit step the same to parent (ArrayCompositeTreeViewDU)
Expand Down
Loading

0 comments on commit 1465945

Please sign in to comment.