Skip to content

Commit 17355d1

Browse files
committed
fix: get attester index from single attestation bytes if cache is used (#7264)
1 parent 4501e08 commit 17355d1

File tree

3 files changed

+34
-4
lines changed

3 files changed

+34
-4
lines changed

packages/beacon-node/src/chain/validation/attestation.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ import {
4343
getAggregationBitsFromAttestationSerialized,
4444
getAttDataFromSignedAggregateAndProofElectra,
4545
getAttDataFromSignedAggregateAndProofPhase0,
46-
getBeaconAttestationGossipIndex,
47-
getCommitteeBitsFromSignedAggregateAndProofElectra,
46+
getAttesterIndexFromSingleAttestationSerialized,
4847
getCommitteeIndexFromSingleAttestationSerialized,
4948
getSignatureFromAttestationSerialized,
5049
} from "../../util/sszBytes.js";
@@ -420,7 +419,18 @@ async function validateAttestationNoSignatureCheck(
420419
});
421420
}
422421
} else {
423-
validatorIndex = (attestationOrCache.attestation as SingleAttestation<ForkPostElectra>).attesterIndex;
422+
if (attestationOrCache.attestation) {
423+
validatorIndex = (attestationOrCache.attestation as SingleAttestation<ForkPostElectra>).attesterIndex;
424+
} else {
425+
const attesterIndex = getAttesterIndexFromSingleAttestationSerialized(attestationOrCache.serializedData);
426+
if (attesterIndex === null) {
427+
throw new AttestationError(GossipAction.REJECT, {
428+
code: AttestationErrorCode.INVALID_SERIALIZED_BYTES,
429+
});
430+
}
431+
validatorIndex = attesterIndex;
432+
}
433+
424434
// [REJECT] The attester is a member of the committee -- i.e.
425435
// `attestation.attester_index in get_beacon_committee(state, attestation.data.slot, index)`.
426436
// If `aggregationBitsElectra` exists, that means we have already cached it. No need to check again

packages/beacon-node/src/util/sszBytes.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
MAX_COMMITTEES_PER_SLOT,
88
isForkPostElectra,
99
} from "@lodestar/params";
10-
import {BLSSignature, CommitteeIndex, RootHex, Slot} from "@lodestar/types";
10+
import {BLSSignature, CommitteeIndex, RootHex, Slot, ValidatorIndex} from "@lodestar/types";
1111

1212
export type BlockRootHex = RootHex;
1313
// pre-electra, AttestationData is used to cache attestations
@@ -54,6 +54,7 @@ const SIGNATURE_SIZE = 96;
5454
const SINGLE_ATTESTATION_ATTDATA_OFFSET = 8 + 8;
5555
const SINGLE_ATTESTATION_SLOT_OFFSET = SINGLE_ATTESTATION_ATTDATA_OFFSET;
5656
const SINGLE_ATTESTATION_COMMITTEE_INDEX_OFFSET = 0;
57+
const SINGLE_ATTESTATION_ATTESTER_INDEX_OFFSET = 8;
5758
const SINGLE_ATTESTATION_BEACON_BLOCK_ROOT_OFFSET = SINGLE_ATTESTATION_ATTDATA_OFFSET + 8 + 8;
5859
const SINGLE_ATTESTATION_SIGNATURE_OFFSET = SINGLE_ATTESTATION_ATTDATA_OFFSET + ATTESTATION_DATA_SIZE;
5960
const SINGLE_ATTESTATION_SIZE = SINGLE_ATTESTATION_SIGNATURE_OFFSET + SIGNATURE_SIZE;
@@ -201,6 +202,19 @@ export function getCommitteeIndexFromSingleAttestationSerialized(
201202
return getSlotFromOffset(data, VARIABLE_FIELD_OFFSET + SLOT_SIZE);
202203
}
203204

205+
/**
206+
* Extract attester index from SingleAttestation serialized bytes.
207+
* Return null if data is not long enough to extract index.
208+
* TODO Electra: Rename getSlotFromOffset to reflect generic usage
209+
*/
210+
export function getAttesterIndexFromSingleAttestationSerialized(data: Uint8Array): ValidatorIndex | null {
211+
if (data.length !== SINGLE_ATTESTATION_SIZE) {
212+
return null;
213+
}
214+
215+
return getSlotFromOffset(data, SINGLE_ATTESTATION_ATTESTER_INDEX_OFFSET);
216+
}
217+
204218
/**
205219
* Extract block root from SingleAttestation serialized bytes.
206220
* Return null if data is not long enough to extract block root.

packages/beacon-node/test/unit/util/sszBytes.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
RootHex,
77
SingleAttestation,
88
Slot,
9+
ValidatorIndex,
910
deneb,
1011
electra,
1112
isElectraSingleAttestation,
@@ -21,6 +22,7 @@ import {
2122
getAttDataFromSignedAggregateAndProofElectra,
2223
getAttDataFromSignedAggregateAndProofPhase0,
2324
getAttDataFromSingleAttestationSerialized,
25+
getAttesterIndexFromSingleAttestationSerialized,
2426
getBlockRootFromAttestationSerialized,
2527
getBlockRootFromSignedAggregateAndProofSerialized,
2628
getBlockRootFromSingleAttestationSerialized,
@@ -49,6 +51,7 @@ describe("SinlgeAttestation SSZ serialized picking", () => {
4951
...electraSingleAttestationFromValues(
5052
4_000_000,
5153
127,
54+
1,
5255
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
5356
200_00,
5457
"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffffffffff"
@@ -68,6 +71,7 @@ describe("SinlgeAttestation SSZ serialized picking", () => {
6871
expect(getCommitteeIndexFromSingleAttestationSerialized(ForkName.electra, bytes)).toEqual(
6972
attestation.committeeIndex
7073
);
74+
expect(getAttesterIndexFromSingleAttestationSerialized(bytes)).toEqual(attestation.attesterIndex);
7175
expect(getBlockRootFromSingleAttestationSerialized(bytes)).toEqual(toRootHex(attestation.data.beaconBlockRoot));
7276
// base64, not hex
7377
expect(getAttDataFromSingleAttestationSerialized(bytes)).toEqual(
@@ -332,6 +336,7 @@ function phase0SingleAttestationFromValues(
332336
function electraSingleAttestationFromValues(
333337
slot: Slot,
334338
committeeIndex: CommitteeIndex,
339+
attesterIndex: ValidatorIndex,
335340
blockRoot: RootHex,
336341
targetEpoch: Epoch,
337342
targetRoot: RootHex
@@ -342,6 +347,7 @@ function electraSingleAttestationFromValues(
342347
attestation.data.target.epoch = targetEpoch;
343348
attestation.data.target.root = fromHex(targetRoot);
344349
attestation.committeeIndex = committeeIndex;
350+
attestation.attesterIndex = attesterIndex;
345351
return attestation;
346352
}
347353

0 commit comments

Comments
 (0)