Skip to content

Commit

Permalink
fix: get attester index from single attestation bytes if cache is used (
Browse files Browse the repository at this point in the history
  • Loading branch information
nflaig committed Nov 29, 2024
1 parent 4501e08 commit 17355d1
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 4 deletions.
16 changes: 13 additions & 3 deletions packages/beacon-node/src/chain/validation/attestation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ import {
getAggregationBitsFromAttestationSerialized,
getAttDataFromSignedAggregateAndProofElectra,
getAttDataFromSignedAggregateAndProofPhase0,
getBeaconAttestationGossipIndex,
getCommitteeBitsFromSignedAggregateAndProofElectra,
getAttesterIndexFromSingleAttestationSerialized,
getCommitteeIndexFromSingleAttestationSerialized,
getSignatureFromAttestationSerialized,
} from "../../util/sszBytes.js";
Expand Down Expand Up @@ -420,7 +419,18 @@ async function validateAttestationNoSignatureCheck(
});
}
} else {
validatorIndex = (attestationOrCache.attestation as SingleAttestation<ForkPostElectra>).attesterIndex;
if (attestationOrCache.attestation) {
validatorIndex = (attestationOrCache.attestation as SingleAttestation<ForkPostElectra>).attesterIndex;
} else {
const attesterIndex = getAttesterIndexFromSingleAttestationSerialized(attestationOrCache.serializedData);
if (attesterIndex === null) {
throw new AttestationError(GossipAction.REJECT, {
code: AttestationErrorCode.INVALID_SERIALIZED_BYTES,
});
}
validatorIndex = attesterIndex;
}

// [REJECT] The attester is a member of the committee -- i.e.
// `attestation.attester_index in get_beacon_committee(state, attestation.data.slot, index)`.
// If `aggregationBitsElectra` exists, that means we have already cached it. No need to check again
Expand Down
16 changes: 15 additions & 1 deletion packages/beacon-node/src/util/sszBytes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
MAX_COMMITTEES_PER_SLOT,
isForkPostElectra,
} from "@lodestar/params";
import {BLSSignature, CommitteeIndex, RootHex, Slot} from "@lodestar/types";
import {BLSSignature, CommitteeIndex, RootHex, Slot, ValidatorIndex} from "@lodestar/types";

export type BlockRootHex = RootHex;
// pre-electra, AttestationData is used to cache attestations
Expand Down Expand Up @@ -54,6 +54,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_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;
const SINGLE_ATTESTATION_SIZE = SINGLE_ATTESTATION_SIGNATURE_OFFSET + SIGNATURE_SIZE;
Expand Down Expand Up @@ -201,6 +202,19 @@ export function getCommitteeIndexFromSingleAttestationSerialized(
return getSlotFromOffset(data, VARIABLE_FIELD_OFFSET + SLOT_SIZE);
}

/**
* Extract attester index from SingleAttestation serialized bytes.
* Return null if data is not long enough to extract index.
* TODO Electra: Rename getSlotFromOffset to reflect generic usage
*/
export function getAttesterIndexFromSingleAttestationSerialized(data: Uint8Array): ValidatorIndex | null {
if (data.length !== SINGLE_ATTESTATION_SIZE) {
return null;
}

return getSlotFromOffset(data, SINGLE_ATTESTATION_ATTESTER_INDEX_OFFSET);
}

/**
* Extract block root from SingleAttestation serialized bytes.
* Return null if data is not long enough to extract block root.
Expand Down
6 changes: 6 additions & 0 deletions packages/beacon-node/test/unit/util/sszBytes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
RootHex,
SingleAttestation,
Slot,
ValidatorIndex,
deneb,
electra,
isElectraSingleAttestation,
Expand All @@ -21,6 +22,7 @@ import {
getAttDataFromSignedAggregateAndProofElectra,
getAttDataFromSignedAggregateAndProofPhase0,
getAttDataFromSingleAttestationSerialized,
getAttesterIndexFromSingleAttestationSerialized,
getBlockRootFromAttestationSerialized,
getBlockRootFromSignedAggregateAndProofSerialized,
getBlockRootFromSingleAttestationSerialized,
Expand Down Expand Up @@ -49,6 +51,7 @@ describe("SinlgeAttestation SSZ serialized picking", () => {
...electraSingleAttestationFromValues(
4_000_000,
127,
1,
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
200_00,
"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffffffffff"
Expand All @@ -68,6 +71,7 @@ describe("SinlgeAttestation SSZ serialized picking", () => {
expect(getCommitteeIndexFromSingleAttestationSerialized(ForkName.electra, bytes)).toEqual(
attestation.committeeIndex
);
expect(getAttesterIndexFromSingleAttestationSerialized(bytes)).toEqual(attestation.attesterIndex);
expect(getBlockRootFromSingleAttestationSerialized(bytes)).toEqual(toRootHex(attestation.data.beaconBlockRoot));
// base64, not hex
expect(getAttDataFromSingleAttestationSerialized(bytes)).toEqual(
Expand Down Expand Up @@ -332,6 +336,7 @@ function phase0SingleAttestationFromValues(
function electraSingleAttestationFromValues(
slot: Slot,
committeeIndex: CommitteeIndex,
attesterIndex: ValidatorIndex,
blockRoot: RootHex,
targetEpoch: Epoch,
targetRoot: RootHex
Expand All @@ -342,6 +347,7 @@ function electraSingleAttestationFromValues(
attestation.data.target.epoch = targetEpoch;
attestation.data.target.root = fromHex(targetRoot);
attestation.committeeIndex = committeeIndex;
attestation.attesterIndex = attesterIndex;
return attestation;
}

Expand Down

0 comments on commit 17355d1

Please sign in to comment.