Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/beacon-node/src/chain/validation/attestation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import {
getAttDataFromSignedAggregateAndProofElectra,
getAttDataFromSignedAggregateAndProofPhase0,
getAttesterIndexFromSingleAttestationSerialized,
getIndexFromSingleAttestationSerialized,
getCommitteeIndexFromSingleAttestationSerialized,
getSignatureFromAttestationSerialized,
getSignatureFromSingleAttestationSerialized,
} from "../../util/sszBytes.js";
Expand Down Expand Up @@ -882,12 +882,12 @@ export function getCommitteeIndexFromAttestationOrBytes(

if (isForkPostElectra(fork)) {
if (isGossipAttestation) {
return getIndexFromSingleAttestationSerialized(ForkName.electra, attestationOrBytes.serializedData);
return getCommitteeIndexFromSingleAttestationSerialized(ForkName.electra, attestationOrBytes.serializedData);
}
return (attestationOrBytes.attestation as SingleAttestation<ForkPostElectra>).committeeIndex;
}
if (isGossipAttestation) {
return getIndexFromSingleAttestationSerialized(ForkName.phase0, attestationOrBytes.serializedData);
return getCommitteeIndexFromSingleAttestationSerialized(ForkName.phase0, attestationOrBytes.serializedData);
}
return (attestationOrBytes.attestation as SingleAttestation<ForkPreElectra>).data.index;
}
Expand Down
10 changes: 5 additions & 5 deletions packages/beacon-node/src/network/processor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import {callInNextEventLoop} from "../../util/eventLoop.js";
import {PeerIdStr} from "../../util/peerId.js";
import {
getBeaconBlockRootFromExecutionPayloadEnvelopeSerialized,
getIndexFromSignedAggregateAndProofSerialized,
getIndexFromSingleAttestationSerialized,
getDataIndexFromSignedAggregateAndProofSerialized,
getDataIndexFromSingleAttestationSerialized,
getParentBlockHashFromGloasSignedBeaconBlockSerialized,
getParentBlockHashFromSignedExecutionPayloadBidSerialized,
getParentBlockRootFromSignedExecutionPayloadBidSerialized,
Expand Down Expand Up @@ -400,10 +400,10 @@ export class NetworkProcessor {
if (root == null) break;
const attIndex =
topicType === GossipType.beacon_attestation
? getIndexFromSingleAttestationSerialized(fork, message.msg.data)
: getIndexFromSignedAggregateAndProofSerialized(message.msg.data);
? getDataIndexFromSingleAttestationSerialized(fork, message.msg.data)
: getDataIndexFromSignedAggregateAndProofSerialized(message.msg.data);
if (attIndex === 1 && !this.chain.forkChoice.hasPayloadHexUnsafe(root)) {
// ptc attestation votes for the payload but the envelope is not yet known
// attestation votes that the payload is available but it is not yet known
this.searchUnknownEnvelope(
{slot, root},
BlockInputSource.network_processor,
Expand Down
50 changes: 38 additions & 12 deletions packages/beacon-node/src/util/sszBytes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export type BlockRootHex = RootHex;
export type AttDataBase64 = string;
// electra, CommitteeBits
export type CommitteeBitsBase64 = string;
/** `attestation.data.index` from gossip-serialized attestations / aggregates */
export type AttDataIndex = number;

// pre-electra
// class Attestation(Container):
Expand Down Expand Up @@ -57,6 +59,7 @@ const SIGNATURE_SIZE = 96;
const SINGLE_ATTESTATION_ATTDATA_OFFSET = 8 + 8;
const SINGLE_ATTESTATION_SLOT_OFFSET = SINGLE_ATTESTATION_ATTDATA_OFFSET;
const SINGLE_ATTESTATION_COMMITTEE_INDEX_OFFSET = 0;
const SINGLE_ATTESTATION_DATA_INDEX_OFFSET = SINGLE_ATTESTATION_ATTDATA_OFFSET + 8;
const SINGLE_ATTESTATION_ATTESTER_INDEX_OFFSET = 8;
const SINGLE_ATTESTATION_BEACON_BLOCK_ROOT_OFFSET = SINGLE_ATTESTATION_ATTDATA_OFFSET + 8 + 8;
const SINGLE_ATTESTATION_SIGNATURE_OFFSET = SINGLE_ATTESTATION_ATTDATA_OFFSET + ATTESTATION_DATA_SIZE;
Expand Down Expand Up @@ -179,13 +182,13 @@ export function getSlotFromSingleAttestationSerialized(data: Uint8Array): Slot |
}

/**
* Extract index from SingleAttestation serialized bytes.
* Post-gloas, `index` field is repurposed:
* - 0 — payload was not available (or attestation is same-slot, where availability is not yet known)
* - 1 - payload was available
* Return null if data is not long enough to extract slot.
* Extract committee index from SingleAttestation serialized bytes.
* Return null if data is not long enough to extract the committee index.
*/
export function getIndexFromSingleAttestationSerialized(fork: ForkName, data: Uint8Array): CommitteeIndex | null {
export function getCommitteeIndexFromSingleAttestationSerialized(
fork: ForkName,
data: Uint8Array
): CommitteeIndex | null {
if (isForkPostElectra(fork)) {
if (data.length !== SINGLE_ATTESTATION_SIZE) {
return null;
Expand All @@ -201,6 +204,29 @@ export function getIndexFromSingleAttestationSerialized(fork: ForkName, data: Ui
return getIndexFromOffset(data, VARIABLE_FIELD_OFFSET + SLOT_SIZE);
}

/**
* Extract data index from SingleAttestation serialized bytes.
* Post-gloas, `data.index` field is repurposed:
* - 0 - payload was not available (or attestation is same-slot, where availability is not yet known)
* - 1 - payload was available
* Return null if data is not long enough to extract the index.
*/
export function getDataIndexFromSingleAttestationSerialized(fork: ForkName, data: Uint8Array): AttDataIndex | null {
if (isForkPostElectra(fork)) {
if (data.length !== SINGLE_ATTESTATION_SIZE) {
return null;
}

return getIndexFromOffset(data, SINGLE_ATTESTATION_DATA_INDEX_OFFSET);
}

if (data.length < VARIABLE_FIELD_OFFSET + SLOT_SIZE + COMMITTEE_INDEX_SIZE) {
return null;
}

return getIndexFromOffset(data, VARIABLE_FIELD_OFFSET + SLOT_SIZE);
}

/**
* Extract attester index from SingleAttestation serialized bytes.
* Return null if data is not long enough to extract index.
Expand Down Expand Up @@ -269,7 +295,7 @@ export function getSignatureFromSingleAttestationSerialized(data: Uint8Array): B
const AGGREGATE_AND_PROOF_OFFSET = 4 + 96;
const AGGREGATE_OFFSET = AGGREGATE_AND_PROOF_OFFSET + 8 + 4 + 96;
const SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET = AGGREGATE_OFFSET + VARIABLE_FIELD_OFFSET;
const SIGNED_AGGREGATE_AND_PROOF_COMMITTEE_INDEX_OFFSET = SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET + SLOT_SIZE;
const SIGNED_AGGREGATE_AND_PROOF_ATTESTATION_DATA_INDEX_OFFSET = SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET + SLOT_SIZE;
const SIGNED_AGGREGATE_AND_PROOF_BLOCK_ROOT_OFFSET = SIGNED_AGGREGATE_AND_PROOF_SLOT_OFFSET + 8 + 8;

/**
Expand Down Expand Up @@ -305,16 +331,16 @@ export function getBlockRootFromSignedAggregateAndProofSerialized(data: Uint8Arr
}

/**
* Extract index from signed aggregate and proof serialized bytes.
* Return null if data is not long enough to extract index.
* Extract data index from signed aggregate and proof serialized bytes.
* Return null if data is not long enough to extract the index.
* This works for both phase0 + electra (index is in attestation data at the same offset).
*/
export function getIndexFromSignedAggregateAndProofSerialized(data: Uint8Array): CommitteeIndex | null {
if (data.length < SIGNED_AGGREGATE_AND_PROOF_COMMITTEE_INDEX_OFFSET + COMMITTEE_INDEX_SIZE) {
export function getDataIndexFromSignedAggregateAndProofSerialized(data: Uint8Array): AttDataIndex | null {
if (data.length < SIGNED_AGGREGATE_AND_PROOF_ATTESTATION_DATA_INDEX_OFFSET + COMMITTEE_INDEX_SIZE) {
return null;
}

return getIndexFromOffset(data, SIGNED_AGGREGATE_AND_PROOF_COMMITTEE_INDEX_OFFSET);
return getIndexFromOffset(data, SIGNED_AGGREGATE_AND_PROOF_ATTESTATION_DATA_INDEX_OFFSET);
}

/**
Expand Down
34 changes: 24 additions & 10 deletions packages/beacon-node/test/unit/util/sszBytes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ import {
getBlockRootFromSignedAggregateAndProofSerialized,
getBlockRootFromSingleAttestationSerialized,
getCommitteeBitsFromSignedAggregateAndProofElectra,
getIndexFromSignedAggregateAndProofSerialized,
getIndexFromSingleAttestationSerialized,
getCommitteeIndexFromSingleAttestationSerialized,
getDataIndexFromSignedAggregateAndProofSerialized,
getDataIndexFromSingleAttestationSerialized,
getLastProcessedSlotFromBeaconStateSerialized,
getParentBlockHashFromGloasSignedBeaconBlockSerialized,
getParentBlockHashFromSignedExecutionPayloadBidSerialized,
Expand Down Expand Up @@ -89,7 +90,10 @@ describe("SinlgeAttestation SSZ serialized picking", () => {

if (isElectra) {
expect(getSlotFromSingleAttestationSerialized(bytes)).toEqual(attestation.data.slot);
expect(getIndexFromSingleAttestationSerialized(ForkName.electra, bytes)).toEqual(attestation.committeeIndex);
expect(getCommitteeIndexFromSingleAttestationSerialized(ForkName.electra, bytes)).toEqual(
attestation.committeeIndex
);
expect(getDataIndexFromSingleAttestationSerialized(ForkName.electra, bytes)).toEqual(attestation.data.index);
expect(getAttesterIndexFromSingleAttestationSerialized(bytes)).toEqual(attestation.attesterIndex);
expect(getBlockRootFromSingleAttestationSerialized(bytes)).toEqual(toRootHex(attestation.data.beaconBlockRoot));
// base64, not hex
Expand All @@ -99,7 +103,10 @@ describe("SinlgeAttestation SSZ serialized picking", () => {
expect(getSignatureFromSingleAttestationSerialized(bytes)).toEqual(attestation.signature);
} else {
expect(getSlotFromAttestationSerialized(bytes)).toBe(attestation.data.slot);
expect(getIndexFromSingleAttestationSerialized(ForkName.phase0, bytes)).toEqual(attestation.data.index);
expect(getCommitteeIndexFromSingleAttestationSerialized(ForkName.phase0, bytes)).toEqual(
attestation.data.index
);
expect(getDataIndexFromSingleAttestationSerialized(ForkName.phase0, bytes)).toEqual(attestation.data.index);
expect(getBlockRootFromAttestationSerialized(bytes)).toBe(toRootHex(attestation.data.beaconBlockRoot));
expect(getAggregationBitsFromAttestationSerialized(bytes)?.toBoolArray()).toEqual(
attestation.aggregationBits.toBoolArray()
Expand Down Expand Up @@ -157,10 +164,17 @@ describe("SinlgeAttestation SSZ serialized picking", () => {
}
});

it("getIndexFromSingleAttestationSerialized - invalid data", () => {
it("getCommitteeIndexFromSingleAttestationSerialized - invalid data", () => {
const invalidCommitteeIndexDataSizes = [0, 4, 11];
for (const size of invalidCommitteeIndexDataSizes) {
expect(getIndexFromSingleAttestationSerialized(ForkName.electra, Buffer.alloc(size))).toBeNull();
expect(getCommitteeIndexFromSingleAttestationSerialized(ForkName.electra, Buffer.alloc(size))).toBeNull();
}
});

it("getDataIndexFromSingleAttestationSerialized - invalid data", () => {
const invalidDataIndexSizes = [0, 4, 11];
for (const size of invalidDataIndexSizes) {
expect(getDataIndexFromSingleAttestationSerialized(ForkName.electra, Buffer.alloc(size))).toBeNull();
}
});

Expand Down Expand Up @@ -300,7 +314,7 @@ describe("electra SignedAggregateAndProof SSZ serialized picking", () => {
});
});

describe("getIndexFromSignedAggregateAndProofSerialized", () => {
describe("getDataIndexFromSignedAggregateAndProofSerialized", () => {
it("phase0 - extracts data.index from aggregate", () => {
const agg = phase0SignedAggregateAndProofFromValues(
4_000_000,
Expand All @@ -310,7 +324,7 @@ describe("getIndexFromSignedAggregateAndProofSerialized", () => {
);
agg.message.aggregate.data.index = 3;
const bytes = ssz.phase0.SignedAggregateAndProof.serialize(agg);
expect(getIndexFromSignedAggregateAndProofSerialized(bytes)).toBe(3);
expect(getDataIndexFromSignedAggregateAndProofSerialized(bytes)).toBe(3);
});

it("electra - extracts data.index from aggregate", () => {
Expand All @@ -322,12 +336,12 @@ describe("getIndexFromSignedAggregateAndProofSerialized", () => {
);
agg.message.aggregate.data.index = 7;
const bytes = ssz.electra.SignedAggregateAndProof.serialize(agg);
expect(getIndexFromSignedAggregateAndProofSerialized(bytes)).toBe(7);
expect(getDataIndexFromSignedAggregateAndProofSerialized(bytes)).toBe(7);
});

it("invalid data returns null", () => {
for (const size of [0, 4, 219]) {
expect(getIndexFromSignedAggregateAndProofSerialized(Buffer.alloc(size))).toBeNull();
expect(getDataIndexFromSignedAggregateAndProofSerialized(Buffer.alloc(size))).toBeNull();
}
});
});
Expand Down
Loading