@lodestar/beacon-node 1.26.0-dev.3dcd668ca9 → 1.26.0-dev.418e81ef2d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/impl/beacon/blocks/index.js +1 -0
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +22 -12
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/config/constants.d.ts +3 -0
- package/lib/api/impl/config/constants.js +4 -1
- package/lib/api/impl/config/constants.js.map +1 -1
- package/lib/chain/errors/attestationError.d.ts +7 -1
- package/lib/chain/errors/attestationError.js +4 -0
- package/lib/chain/errors/attestationError.js.map +1 -1
- package/lib/chain/opPools/attestationPool.d.ts +2 -2
- package/lib/chain/opPools/attestationPool.js +20 -14
- package/lib/chain/opPools/attestationPool.js.map +1 -1
- package/lib/chain/opPools/opPool.d.ts +3 -2
- package/lib/chain/opPools/opPool.js +8 -8
- package/lib/chain/opPools/opPool.js.map +1 -1
- package/lib/chain/seenCache/seenAttestationData.d.ts +15 -7
- package/lib/chain/seenCache/seenAttestationData.js +33 -14
- package/lib/chain/seenCache/seenAttestationData.js.map +1 -1
- package/lib/chain/validation/aggregateAndProof.js +3 -6
- package/lib/chain/validation/aggregateAndProof.js.map +1 -1
- package/lib/chain/validation/attestation.d.ts +18 -10
- package/lib/chain/validation/attestation.js +129 -81
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/attesterSlashing.d.ts +4 -4
- package/lib/chain/validation/attesterSlashing.js +1 -2
- package/lib/chain/validation/attesterSlashing.js.map +1 -1
- package/lib/chain/validation/blobSidecar.d.ts +2 -1
- package/lib/chain/validation/blobSidecar.js +8 -7
- package/lib/chain/validation/blobSidecar.js.map +1 -1
- package/lib/chain/validation/block.js +3 -2
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/voluntaryExit.js +1 -1
- package/lib/chain/validation/voluntaryExit.js.map +1 -1
- package/lib/db/buckets.d.ts +1 -1
- package/lib/db/buckets.js +1 -1
- package/lib/db/buckets.js.map +1 -1
- package/lib/db/repositories/attesterSlashing.d.ts +2 -2
- package/lib/db/repositories/attesterSlashing.js +8 -2
- package/lib/db/repositories/attesterSlashing.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +3 -1
- package/lib/execution/engine/interface.js +4 -0
- package/lib/execution/engine/interface.js.map +1 -1
- package/lib/execution/engine/types.d.ts +2 -2
- package/lib/execution/engine/types.js +67 -15
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/metrics/metrics/beacon.d.ts +1 -1
- package/lib/metrics/metrics/beacon.js +3 -3
- package/lib/metrics/metrics/beacon.js.map +1 -1
- package/lib/metrics/validatorMonitor.js +4 -0
- package/lib/metrics/validatorMonitor.js.map +1 -1
- package/lib/network/gossip/interface.d.ts +5 -5
- package/lib/network/gossip/interface.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +962 -956
- package/lib/network/gossip/topic.js +22 -3
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/interface.d.ts +3 -3
- package/lib/network/network.d.ts +3 -3
- package/lib/network/network.js +4 -2
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/extractSlotRootFns.js +4 -4
- package/lib/network/processor/extractSlotRootFns.js.map +1 -1
- package/lib/network/processor/gossipHandlers.js +22 -12
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/gossipQueues/index.js +2 -3
- package/lib/network/processor/gossipQueues/index.js.map +1 -1
- package/lib/network/processor/index.js +1 -1
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/processor/types.d.ts +2 -1
- package/lib/network/reqresp/ReqRespBeaconNode.js +20 -13
- package/lib/network/reqresp/ReqRespBeaconNode.js.map +1 -1
- package/lib/network/reqresp/beaconBlocksMaybeBlobsByRoot.js +2 -2
- package/lib/network/reqresp/beaconBlocksMaybeBlobsByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts +2 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +6 -5
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts +2 -1
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js +6 -5
- package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/index.js +2 -1
- package/lib/network/reqresp/handlers/index.js.map +1 -1
- package/lib/network/reqresp/protocols.d.ts +16 -15
- package/lib/network/reqresp/protocols.js +3 -3
- package/lib/network/reqresp/protocols.js.map +1 -1
- package/lib/network/reqresp/rateLimit.d.ts +3 -2
- package/lib/network/reqresp/rateLimit.js +14 -15
- package/lib/network/reqresp/rateLimit.js.map +1 -1
- package/lib/network/reqresp/types.d.ts +2 -2
- package/lib/network/reqresp/types.js +2 -2
- package/lib/network/reqresp/types.js.map +1 -1
- package/lib/sync/range/chain.js +8 -3
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/util/sszBytes.d.ts +42 -7
- package/lib/util/sszBytes.js +110 -15
- package/lib/util/sszBytes.js.map +1 -1
- package/lib/util/types.d.ts +3 -2
- package/lib/util/types.js +1 -1
- package/lib/util/types.js.map +1 -1
- package/package.json +17 -17
|
@@ -9,6 +9,9 @@ export var RejectReason;
|
|
|
9
9
|
// attestation data is already known
|
|
10
10
|
RejectReason["already_known"] = "already_known";
|
|
11
11
|
})(RejectReason || (RejectReason = {}));
|
|
12
|
+
// For pre-electra, there is no committeeIndex in SingleAttestation, so we hard code it to 0
|
|
13
|
+
// AttDataBase64 has committeeIndex instead
|
|
14
|
+
export const PRE_ELECTRA_SINGLE_ATTESTATION_COMMITTEE_INDEX = 0;
|
|
12
15
|
/**
|
|
13
16
|
* There are maximum 64 committees per slot, assuming 1 committee may have up to 3 different data due to some nodes
|
|
14
17
|
* are not up to date, we can have up to 192 different attestation data per slot.
|
|
@@ -31,31 +34,42 @@ export class SeenAttestationDatas {
|
|
|
31
34
|
this.metrics = metrics;
|
|
32
35
|
this.cacheSlotDistance = cacheSlotDistance;
|
|
33
36
|
this.maxCacheSizePerSlot = maxCacheSizePerSlot;
|
|
34
|
-
this.
|
|
37
|
+
this.cacheEntryByAttDataByIndexBySlot = new MapDef(() => new MapDef(() => new Map()));
|
|
35
38
|
this.lowestPermissibleSlot = 0;
|
|
36
39
|
metrics?.seenCache.attestationData.totalSlot.addCollect(() => this.onScrapeLodestarMetrics(metrics));
|
|
37
40
|
}
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Add an AttestationDataCacheEntry to the cache.
|
|
43
|
+
* - preElectra: add(slot, PRE_ELECTRA_SINGLE_ATTESTATION_COMMITTEE_INDEX, attDataBase64, cacheEntry)
|
|
44
|
+
* - electra: add(slot, committeeIndex, attDataBase64, cacheEntry)
|
|
45
|
+
*/
|
|
46
|
+
add(slot, committeeIndex, attDataBase64, cacheEntry) {
|
|
40
47
|
if (slot < this.lowestPermissibleSlot) {
|
|
41
48
|
this.metrics?.seenCache.attestationData.reject.inc({ reason: RejectReason.too_old });
|
|
42
49
|
return InsertOutcome.Old;
|
|
43
50
|
}
|
|
44
|
-
const
|
|
45
|
-
|
|
51
|
+
const cacheEntryByAttDataByIndex = this.cacheEntryByAttDataByIndexBySlot.getOrDefault(slot);
|
|
52
|
+
const cacheEntryByAttData = cacheEntryByAttDataByIndex.getOrDefault(committeeIndex);
|
|
53
|
+
if (cacheEntryByAttData.has(attDataBase64)) {
|
|
46
54
|
this.metrics?.seenCache.attestationData.reject.inc({ reason: RejectReason.already_known });
|
|
47
55
|
return InsertOutcome.AlreadyKnown;
|
|
48
56
|
}
|
|
49
|
-
if (
|
|
57
|
+
if (cacheEntryByAttData.size >= this.maxCacheSizePerSlot) {
|
|
50
58
|
this.metrics?.seenCache.attestationData.reject.inc({ reason: RejectReason.reached_limit });
|
|
51
59
|
return InsertOutcome.ReachLimit;
|
|
52
60
|
}
|
|
53
|
-
|
|
61
|
+
cacheEntryByAttData.set(attDataBase64, cacheEntry);
|
|
54
62
|
return InsertOutcome.NewData;
|
|
55
63
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
/**
|
|
65
|
+
* Get an AttestationDataCacheEntry from the cache.
|
|
66
|
+
* - preElectra: get(slot, PRE_ELECTRA_SINGLE_ATTESTATION_COMMITTEE_INDEX, attDataBase64)
|
|
67
|
+
* - electra: get(slot, committeeIndex, attDataBase64)
|
|
68
|
+
*/
|
|
69
|
+
get(slot, committeeIndex, attDataBase64) {
|
|
70
|
+
const cacheEntryByAttDataByIndex = this.cacheEntryByAttDataByIndexBySlot.get(slot);
|
|
71
|
+
const cacheEntryByAttData = cacheEntryByAttDataByIndex?.get(committeeIndex);
|
|
72
|
+
const cacheEntry = cacheEntryByAttData?.get(attDataBase64);
|
|
59
73
|
if (cacheEntry) {
|
|
60
74
|
this.metrics?.seenCache.attestationData.hit.inc();
|
|
61
75
|
}
|
|
@@ -66,18 +80,23 @@ export class SeenAttestationDatas {
|
|
|
66
80
|
}
|
|
67
81
|
onSlot(clockSlot) {
|
|
68
82
|
this.lowestPermissibleSlot = Math.max(clockSlot - this.cacheSlotDistance, 0);
|
|
69
|
-
for (const slot of this.
|
|
83
|
+
for (const slot of this.cacheEntryByAttDataByIndexBySlot.keys()) {
|
|
70
84
|
if (slot < this.lowestPermissibleSlot) {
|
|
71
|
-
this.
|
|
85
|
+
this.cacheEntryByAttDataByIndexBySlot.delete(slot);
|
|
72
86
|
}
|
|
73
87
|
}
|
|
74
88
|
}
|
|
75
89
|
onScrapeLodestarMetrics(metrics) {
|
|
76
|
-
metrics?.seenCache.attestationData.totalSlot.set(this.
|
|
90
|
+
metrics?.seenCache.attestationData.totalSlot.set(this.cacheEntryByAttDataByIndexBySlot.size);
|
|
77
91
|
// tracking number of attestation data at current slot may not be correct if scrape time is not at the end of slot
|
|
78
92
|
// so we track it at the previous slot
|
|
79
93
|
const previousSlot = this.lowestPermissibleSlot + this.cacheSlotDistance - 1;
|
|
80
|
-
|
|
94
|
+
const cacheEntryByAttDataByIndex = this.cacheEntryByAttDataByIndexBySlot.get(previousSlot);
|
|
95
|
+
let count = 0;
|
|
96
|
+
for (const cacheEntryByAttDataBase64 of cacheEntryByAttDataByIndex?.values() ?? []) {
|
|
97
|
+
count += cacheEntryByAttDataBase64.size;
|
|
98
|
+
}
|
|
99
|
+
metrics?.seenCache.attestationData.countPerSlot.set(count);
|
|
81
100
|
}
|
|
82
101
|
}
|
|
83
102
|
//# sourceMappingURL=seenAttestationData.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"seenAttestationData.js","sourceRoot":"","sources":["../../../src/chain/seenCache/seenAttestationData.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,MAAM,EAAC,MAAM,iBAAiB,CAAC;AAEvC,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"seenAttestationData.js","sourceRoot":"","sources":["../../../src/chain/seenCache/seenAttestationData.ts"],"names":[],"mappings":"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"}
|
|
@@ -33,8 +33,6 @@ async function validateAggregateAndProof(fork, chain, signedAggregateAndProof, s
|
|
|
33
33
|
const { aggregationBits } = aggregate;
|
|
34
34
|
const attData = aggregate.data;
|
|
35
35
|
const attSlot = attData.slot;
|
|
36
|
-
const seenAttDataKey = serializedData ? getSeenAttDataKeyFromSignedAggregateAndProof(fork, serializedData) : null;
|
|
37
|
-
const cachedAttData = seenAttDataKey ? chain.seenAttestationDatas.get(attSlot, seenAttDataKey) : null;
|
|
38
36
|
let attIndex;
|
|
39
37
|
if (ForkSeq[fork] >= ForkSeq.electra) {
|
|
40
38
|
attIndex = aggregate.committeeBits.getSingleTrueBit();
|
|
@@ -50,6 +48,8 @@ async function validateAggregateAndProof(fork, chain, signedAggregateAndProof, s
|
|
|
50
48
|
else {
|
|
51
49
|
attIndex = attData.index;
|
|
52
50
|
}
|
|
51
|
+
const seenAttDataKey = serializedData ? getSeenAttDataKeyFromSignedAggregateAndProof(fork, serializedData) : null;
|
|
52
|
+
const cachedAttData = seenAttDataKey ? chain.seenAttestationDatas.get(attSlot, attIndex, seenAttDataKey) : null;
|
|
53
53
|
const attEpoch = computeEpochAtSlot(attSlot);
|
|
54
54
|
const attTarget = attData.target;
|
|
55
55
|
const targetEpoch = attTarget.epoch;
|
|
@@ -109,14 +109,11 @@ async function validateAggregateAndProof(fork, chain, signedAggregateAndProof, s
|
|
|
109
109
|
throw new AttestationError(GossipAction.REJECT, { code: AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS });
|
|
110
110
|
}
|
|
111
111
|
const attestingIndices = aggregate.aggregationBits.intersectValues(committeeIndices);
|
|
112
|
-
const
|
|
112
|
+
const indexedAttestation = {
|
|
113
113
|
attestingIndices,
|
|
114
114
|
data: attData,
|
|
115
115
|
signature: aggregate.signature,
|
|
116
116
|
};
|
|
117
|
-
const indexedAttestation = ForkSeq[fork] >= ForkSeq.electra
|
|
118
|
-
? indexedAttestationContent
|
|
119
|
-
: indexedAttestationContent;
|
|
120
117
|
// TODO: Check this before regen
|
|
121
118
|
// [REJECT] The attestation has participants -- that is,
|
|
122
119
|
// len(get_attesting_indices(state, aggregate.data, aggregate.aggregation_bits)) >= 1.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aggregateAndProof.js","sourceRoot":"","sources":["../../../src/chain/validation/aggregateAndProof.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,OAAO,EAAC,MAAM,kBAAkB,CAAC;AACnD,OAAO,EACL,kBAAkB,EAClB,yCAAyC,EACzC,+BAA+B,GAChC,MAAM,4BAA4B,CAAC;AACpC,OAAO,
|
|
1
|
+
{"version":3,"file":"aggregateAndProof.js","sourceRoot":"","sources":["../../../src/chain/validation/aggregateAndProof.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { BeaconConfig } from "@lodestar/config";
|
|
2
2
|
import { ProtoBlock } from "@lodestar/fork-choice";
|
|
3
|
-
import { ForkName } from "@lodestar/params";
|
|
3
|
+
import { ForkName, ForkPostElectra, ForkPreElectra } from "@lodestar/params";
|
|
4
4
|
import { EpochShuffling, SingleSignatureSet } from "@lodestar/state-transition";
|
|
5
|
-
import {
|
|
5
|
+
import { CommitteeIndex, Epoch, IndexedAttestation, Root, RootHex, SingleAttestation, Slot, SubnetID, ValidatorIndex, phase0 } from "@lodestar/types";
|
|
6
6
|
import { Result } from "../../util/wrapError.js";
|
|
7
7
|
import { IBeaconChain } from "../interface.js";
|
|
8
8
|
import { RegenCaller } from "../regen/index.js";
|
|
@@ -12,16 +12,18 @@ export type BatchResult = {
|
|
|
12
12
|
batchableBls: boolean;
|
|
13
13
|
};
|
|
14
14
|
export type AttestationValidationResult = {
|
|
15
|
-
attestation:
|
|
15
|
+
attestation: SingleAttestation;
|
|
16
16
|
indexedAttestation: IndexedAttestation;
|
|
17
17
|
subnet: SubnetID;
|
|
18
18
|
attDataRootHex: RootHex;
|
|
19
19
|
committeeIndex: CommitteeIndex;
|
|
20
|
+
committeeValidatorIndex: number;
|
|
21
|
+
committeeSize: number;
|
|
20
22
|
};
|
|
21
23
|
export type AttestationOrBytes = ApiAttestation | GossipAttestation;
|
|
22
24
|
/** attestation from api */
|
|
23
25
|
export type ApiAttestation = {
|
|
24
|
-
attestation:
|
|
26
|
+
attestation: SingleAttestation;
|
|
25
27
|
serializedData: null;
|
|
26
28
|
};
|
|
27
29
|
/** attestation from gossip */
|
|
@@ -50,7 +52,7 @@ export declare function validateGossipAttestationsSameAttData(fork: ForkName, ch
|
|
|
50
52
|
*/
|
|
51
53
|
export declare function validateApiAttestation(fork: ForkName, chain: IBeaconChain, attestationOrBytes: ApiAttestation): Promise<AttestationValidationResult>;
|
|
52
54
|
/**
|
|
53
|
-
* Only deserialize the attestation if needed, use the cached AttestationData instead
|
|
55
|
+
* Only deserialize the single attestation if needed, use the cached AttestationData instead
|
|
54
56
|
* This is to avoid deserializing similar attestation multiple times which could help the gc
|
|
55
57
|
*/
|
|
56
58
|
declare function validateAttestationNoSignatureCheck(fork: ForkName, chain: IBeaconChain, attestationOrBytes: AttestationOrBytes,
|
|
@@ -98,15 +100,21 @@ export declare function getCommitteeIndices(shuffling: EpochShuffling, attestati
|
|
|
98
100
|
export declare function computeSubnetForSlot(shuffling: EpochShuffling, slot: number, committeeIndex: number): SubnetID;
|
|
99
101
|
/**
|
|
100
102
|
* Return fork-dependent seen attestation key
|
|
101
|
-
* - for pre-electra, it's the AttestationData base64
|
|
102
|
-
* - for electra and later, it's the AttestationData base64
|
|
103
|
+
* - for pre-electra, it's the AttestationData base64 from Attestation
|
|
104
|
+
* - for electra and later, it's the AttestationData base64 from SingleAttestation
|
|
105
|
+
* - consumers need to also pass slot + committeeIndex to get the correct SeenAttestationData
|
|
103
106
|
*/
|
|
104
|
-
export declare function getSeenAttDataKeyFromGossipAttestation(
|
|
107
|
+
export declare function getSeenAttDataKeyFromGossipAttestation(attestation: GossipAttestation): SeenAttDataKey | null;
|
|
105
108
|
/**
|
|
106
109
|
* Extract attestation data key from SignedAggregateAndProof Uint8Array to use cached data from SeenAttestationDatas
|
|
107
|
-
* - for pre-electra, it's the AttestationData base64
|
|
108
|
-
* -
|
|
110
|
+
* - for both electra + pre-electra, it's the AttestationData base64
|
|
111
|
+
* - consumers need to also pass slot + committeeIndex to get the correct SeenAttestationData
|
|
109
112
|
*/
|
|
110
113
|
export declare function getSeenAttDataKeyFromSignedAggregateAndProof(fork: ForkName, aggregateAndProof: Uint8Array): SeenAttDataKey | null;
|
|
114
|
+
export declare function getCommitteeIndexFromAttestationOrBytes(fork: ForkName, attestationOrBytes: AttestationOrBytes): CommitteeIndex | null;
|
|
115
|
+
/**
|
|
116
|
+
* Convert pre-electra single attestation (`phase0.Attestation`) to post-electra `SingleAttestation`
|
|
117
|
+
*/
|
|
118
|
+
export declare function toElectraSingleAttestation(attestation: SingleAttestation<ForkPreElectra>, attesterIndex: ValidatorIndex): SingleAttestation<ForkPostElectra>;
|
|
111
119
|
export {};
|
|
112
120
|
//# sourceMappingURL=attestation.d.ts.map
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { ATTESTATION_SUBNET_COUNT, DOMAIN_BEACON_ATTESTER, ForkSeq, SLOTS_PER_EPOCH, isForkPostElectra, } from "@lodestar/params";
|
|
1
|
+
import { ATTESTATION_SUBNET_COUNT, DOMAIN_BEACON_ATTESTER, ForkName, ForkSeq, SLOTS_PER_EPOCH, isForkPostElectra, } from "@lodestar/params";
|
|
2
2
|
import { EpochCacheError, EpochCacheErrorCode, computeEpochAtSlot, computeSigningRoot, computeStartSlotAtEpoch, createSingleSignatureSetFromComponents, } from "@lodestar/state-transition";
|
|
3
|
-
import {
|
|
4
|
-
import { toRootHex } from "@lodestar/utils";
|
|
3
|
+
import { isElectraSingleAttestation, ssz, } from "@lodestar/types";
|
|
4
|
+
import { assert, toRootHex } from "@lodestar/utils";
|
|
5
5
|
import { MAXIMUM_GOSSIP_CLOCK_DISPARITY_SEC } from "../../constants/index.js";
|
|
6
|
-
import {
|
|
6
|
+
import { sszDeserializeSingleAttestation } from "../../network/gossip/topic.js";
|
|
7
7
|
import { getShufflingDependentRoot } from "../../util/dependentRoot.js";
|
|
8
|
-
import { getAggregationBitsFromAttestationSerialized, getAttDataFromSignedAggregateAndProofElectra, getAttDataFromSignedAggregateAndProofPhase0,
|
|
8
|
+
import { getAggregationBitsFromAttestationSerialized, getAttDataFromSignedAggregateAndProofElectra, getAttDataFromSignedAggregateAndProofPhase0, getAttesterIndexFromSingleAttestationSerialized, getCommitteeIndexFromSingleAttestationSerialized, getSignatureFromAttestationSerialized, getSignatureFromSingleAttestationSerialized, } from "../../util/sszBytes.js";
|
|
9
9
|
import { wrapError } from "../../util/wrapError.js";
|
|
10
10
|
import { AttestationError, AttestationErrorCode, GossipAction } from "../errors/index.js";
|
|
11
11
|
import { RegenCaller } from "../regen/index.js";
|
|
12
|
+
import { PRE_ELECTRA_SINGLE_ATTESTATION_COMMITTEE_INDEX, } from "../seenCache/seenAttestationData.js";
|
|
12
13
|
/**
|
|
13
14
|
* Verify gossip attestations of the same attestation data. The main advantage is we can batch verify bls signatures
|
|
14
15
|
* through verifySignatureSetsSameMessage bls api to improve performance.
|
|
@@ -127,7 +128,7 @@ export async function validateApiAttestation(fork, chain, attestationOrBytes) {
|
|
|
127
128
|
}
|
|
128
129
|
}
|
|
129
130
|
/**
|
|
130
|
-
* Only deserialize the attestation if needed, use the cached AttestationData instead
|
|
131
|
+
* Only deserialize the single attestation if needed, use the cached AttestationData instead
|
|
131
132
|
* This is to avoid deserializing similar attestation multiple times which could help the gc
|
|
132
133
|
*/
|
|
133
134
|
async function validateAttestationNoSignatureCheck(fork, chain, attestationOrBytes,
|
|
@@ -146,10 +147,13 @@ subnet) {
|
|
|
146
147
|
if (attestationOrBytes.serializedData) {
|
|
147
148
|
// gossip
|
|
148
149
|
const attSlot = attestationOrBytes.attSlot;
|
|
149
|
-
attDataKey = getSeenAttDataKeyFromGossipAttestation(
|
|
150
|
-
const
|
|
150
|
+
attDataKey = getSeenAttDataKeyFromGossipAttestation(attestationOrBytes);
|
|
151
|
+
const committeeIndexForLookup = isForkPostElectra(fork)
|
|
152
|
+
? (getCommitteeIndexFromAttestationOrBytes(fork, attestationOrBytes) ?? 0)
|
|
153
|
+
: PRE_ELECTRA_SINGLE_ATTESTATION_COMMITTEE_INDEX;
|
|
154
|
+
const cachedAttData = attDataKey !== null ? chain.seenAttestationDatas.get(attSlot, committeeIndexForLookup, attDataKey) : null;
|
|
151
155
|
if (cachedAttData === null) {
|
|
152
|
-
const attestation =
|
|
156
|
+
const attestation = sszDeserializeSingleAttestation(fork, attestationOrBytes.serializedData);
|
|
153
157
|
// only deserialize on the first AttestationData that's not cached
|
|
154
158
|
attestationOrCache = { attestation, cache: null };
|
|
155
159
|
}
|
|
@@ -171,19 +175,10 @@ subnet) {
|
|
|
171
175
|
const targetEpoch = attTarget.epoch;
|
|
172
176
|
let committeeIndex;
|
|
173
177
|
if (attestationOrCache.attestation) {
|
|
174
|
-
if (
|
|
178
|
+
if (isElectraSingleAttestation(attestationOrCache.attestation)) {
|
|
175
179
|
// api or first time validation of a gossip attestation
|
|
176
|
-
|
|
177
|
-
//
|
|
178
|
-
if (committeeBits == null) {
|
|
179
|
-
throw new AttestationError(GossipAction.REJECT, { code: AttestationErrorCode.INVALID_SERIALIZED_BYTES });
|
|
180
|
-
}
|
|
181
|
-
committeeIndex = committeeBits.getSingleTrueBit();
|
|
182
|
-
// [REJECT] len(committee_indices) == 1, where committee_indices = get_committee_indices(aggregate)
|
|
183
|
-
if (committeeIndex === null) {
|
|
184
|
-
throw new AttestationError(GossipAction.REJECT, { code: AttestationErrorCode.NOT_EXACTLY_ONE_COMMITTEE_BIT_SET });
|
|
185
|
-
}
|
|
186
|
-
// [REJECT] aggregate.data.index == 0
|
|
180
|
+
committeeIndex = attestationOrCache.attestation.committeeIndex;
|
|
181
|
+
// [REJECT] attestation.data.index == 0
|
|
187
182
|
if (attData.index !== 0) {
|
|
188
183
|
throw new AttestationError(GossipAction.REJECT, { code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX });
|
|
189
184
|
}
|
|
@@ -210,22 +205,27 @@ subnet) {
|
|
|
210
205
|
// (a client MAY queue future attestations for processing at the appropriate slot).
|
|
211
206
|
verifyPropagationSlotRange(fork, chain, attestationOrCache.attestation.data.slot);
|
|
212
207
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
:
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
208
|
+
let aggregationBits = null;
|
|
209
|
+
let committeeValidatorIndex = null;
|
|
210
|
+
if (!isForkPostElectra(fork)) {
|
|
211
|
+
// [REJECT] The attestation is unaggregated -- that is, it has exactly one participating validator
|
|
212
|
+
// (len([bit for bit in attestation.aggregation_bits if bit]) == 1, i.e. exactly 1 bit is set).
|
|
213
|
+
// > TODO: Do this check **before** getting the target state but don't recompute zipIndexes
|
|
214
|
+
aggregationBits = attestationOrCache.attestation
|
|
215
|
+
? attestationOrCache.attestation.aggregationBits
|
|
216
|
+
: getAggregationBitsFromAttestationSerialized(attestationOrCache.serializedData);
|
|
217
|
+
if (aggregationBits === null) {
|
|
218
|
+
throw new AttestationError(GossipAction.REJECT, {
|
|
219
|
+
code: AttestationErrorCode.INVALID_SERIALIZED_BYTES,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
const bitIndex = aggregationBits.getSingleTrueBit();
|
|
223
|
+
if (bitIndex === null) {
|
|
224
|
+
throw new AttestationError(GossipAction.REJECT, {
|
|
225
|
+
code: AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET,
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
committeeValidatorIndex = bitIndex;
|
|
229
229
|
}
|
|
230
230
|
let committeeValidatorIndices;
|
|
231
231
|
let getSigningRoot;
|
|
@@ -259,14 +259,43 @@ subnet) {
|
|
|
259
259
|
getSigningRoot = () => getAttestationDataSigningRoot(chain.config, attData);
|
|
260
260
|
expectedSubnet = computeSubnetForSlot(shuffling, attSlot, committeeIndex);
|
|
261
261
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
262
|
+
let validatorIndex;
|
|
263
|
+
if (!isForkPostElectra(fork)) {
|
|
264
|
+
// The validity of aggregation bits are already checked above
|
|
265
|
+
assert.notNull(aggregationBits);
|
|
266
|
+
assert.notNull(committeeValidatorIndex);
|
|
267
|
+
validatorIndex = committeeValidatorIndices[committeeValidatorIndex];
|
|
268
|
+
// [REJECT] The number of aggregation bits matches the committee size
|
|
269
|
+
// -- i.e. len(attestation.aggregation_bits) == len(get_beacon_committee(state, data.slot, data.index)).
|
|
270
|
+
// > TODO: Is this necessary? Lighthouse does not do this check.
|
|
271
|
+
if (aggregationBits.bitLen !== committeeValidatorIndices.length) {
|
|
272
|
+
throw new AttestationError(GossipAction.REJECT, {
|
|
273
|
+
code: AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS,
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
if (attestationOrCache.attestation) {
|
|
279
|
+
validatorIndex = attestationOrCache.attestation.attesterIndex;
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
const attesterIndex = getAttesterIndexFromSingleAttestationSerialized(attestationOrCache.serializedData);
|
|
283
|
+
if (attesterIndex === null) {
|
|
284
|
+
throw new AttestationError(GossipAction.REJECT, {
|
|
285
|
+
code: AttestationErrorCode.INVALID_SERIALIZED_BYTES,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
validatorIndex = attesterIndex;
|
|
289
|
+
}
|
|
290
|
+
// [REJECT] The attester is a member of the committee -- i.e.
|
|
291
|
+
// `attestation.attester_index in get_beacon_committee(state, attestation.data.slot, index)`.
|
|
292
|
+
// Position of the validator in its committee
|
|
293
|
+
committeeValidatorIndex = committeeValidatorIndices.indexOf(validatorIndex);
|
|
294
|
+
if (committeeValidatorIndex === -1) {
|
|
295
|
+
throw new AttestationError(GossipAction.REJECT, {
|
|
296
|
+
code: AttestationErrorCode.ATTESTER_NOT_IN_COMMITTEE,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
270
299
|
}
|
|
271
300
|
// LH > verify_middle_checks
|
|
272
301
|
// Run the checks that apply to the indexed attestation before the signature is checked.
|
|
@@ -298,31 +327,26 @@ subnet) {
|
|
|
298
327
|
let attDataRootHex;
|
|
299
328
|
const signature = attestationOrCache.attestation
|
|
300
329
|
? attestationOrCache.attestation.signature
|
|
301
|
-
:
|
|
330
|
+
: !isForkPostElectra(fork)
|
|
331
|
+
? getSignatureFromAttestationSerialized(attestationOrCache.serializedData)
|
|
332
|
+
: getSignatureFromSingleAttestationSerialized(attestationOrCache.serializedData);
|
|
302
333
|
if (signature === null) {
|
|
303
334
|
throw new AttestationError(GossipAction.REJECT, {
|
|
304
335
|
code: AttestationErrorCode.INVALID_SERIALIZED_BYTES,
|
|
305
336
|
});
|
|
306
337
|
}
|
|
307
|
-
let committeeBits = undefined;
|
|
308
338
|
if (attestationOrCache.cache) {
|
|
309
339
|
// there could be up to 6% of cpu time to compute signing root if we don't clone the signature set
|
|
310
340
|
signatureSet = createSingleSignatureSetFromComponents(chain.index2pubkey[validatorIndex], attestationOrCache.cache.signingRoot, signature);
|
|
311
341
|
attDataRootHex = attestationOrCache.cache.attDataRootHex;
|
|
312
|
-
committeeBits = attestationOrCache.cache.committeeBits;
|
|
313
342
|
}
|
|
314
343
|
else {
|
|
315
344
|
signatureSet = createSingleSignatureSetFromComponents(chain.index2pubkey[validatorIndex], getSigningRoot(), signature);
|
|
316
345
|
// add cached attestation data before verifying signature
|
|
317
346
|
attDataRootHex = toRootHex(ssz.phase0.AttestationData.hashTreeRoot(attData));
|
|
318
|
-
// if attestation is phase0 the committeeBits is undefined anyway
|
|
319
|
-
committeeBits = isElectraAttestation(attestationOrCache.attestation)
|
|
320
|
-
? attestationOrCache.attestation.committeeBits.clone()
|
|
321
|
-
: undefined;
|
|
322
347
|
if (attDataKey) {
|
|
323
|
-
chain.seenAttestationDatas.add(attSlot, attDataKey, {
|
|
348
|
+
chain.seenAttestationDatas.add(attSlot, committeeIndex, attDataKey, {
|
|
324
349
|
committeeValidatorIndices,
|
|
325
|
-
committeeBits,
|
|
326
350
|
committeeIndex,
|
|
327
351
|
signingRoot: signatureSet.signingRoot,
|
|
328
352
|
subnet: expectedSubnet,
|
|
@@ -334,20 +358,26 @@ subnet) {
|
|
|
334
358
|
}
|
|
335
359
|
}
|
|
336
360
|
// no signature check, leave that for step1
|
|
337
|
-
const
|
|
361
|
+
const indexedAttestation = {
|
|
338
362
|
attestingIndices,
|
|
339
363
|
data: attData,
|
|
340
364
|
signature,
|
|
341
365
|
};
|
|
342
|
-
const
|
|
343
|
-
?
|
|
344
|
-
:
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
366
|
+
const attestation = attestationOrCache.attestation
|
|
367
|
+
? attestationOrCache.attestation
|
|
368
|
+
: !isForkPostElectra(fork)
|
|
369
|
+
? {
|
|
370
|
+
// Aggregation bits are already asserted above to not be null
|
|
371
|
+
aggregationBits: aggregationBits,
|
|
372
|
+
data: attData,
|
|
373
|
+
signature,
|
|
374
|
+
}
|
|
375
|
+
: {
|
|
376
|
+
committeeIndex,
|
|
377
|
+
attesterIndex: validatorIndex,
|
|
378
|
+
data: attData,
|
|
379
|
+
signature,
|
|
380
|
+
};
|
|
351
381
|
return {
|
|
352
382
|
attestation,
|
|
353
383
|
indexedAttestation,
|
|
@@ -356,6 +386,8 @@ subnet) {
|
|
|
356
386
|
signatureSet,
|
|
357
387
|
validatorIndex,
|
|
358
388
|
committeeIndex,
|
|
389
|
+
committeeValidatorIndex,
|
|
390
|
+
committeeSize: committeeValidatorIndices.length,
|
|
359
391
|
};
|
|
360
392
|
}
|
|
361
393
|
/**
|
|
@@ -576,30 +608,46 @@ export function computeSubnetForSlot(shuffling, slot, committeeIndex) {
|
|
|
576
608
|
}
|
|
577
609
|
/**
|
|
578
610
|
* Return fork-dependent seen attestation key
|
|
579
|
-
* - for pre-electra, it's the AttestationData base64
|
|
580
|
-
* - for electra and later, it's the AttestationData base64
|
|
611
|
+
* - for pre-electra, it's the AttestationData base64 from Attestation
|
|
612
|
+
* - for electra and later, it's the AttestationData base64 from SingleAttestation
|
|
613
|
+
* - consumers need to also pass slot + committeeIndex to get the correct SeenAttestationData
|
|
581
614
|
*/
|
|
582
|
-
export function getSeenAttDataKeyFromGossipAttestation(
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
const committeeBits = getCommitteeBitsFromAttestationSerialized(serializedData);
|
|
586
|
-
return attDataBase64 && committeeBits ? attDataBase64 + committeeBits : null;
|
|
587
|
-
}
|
|
588
|
-
// pre-electra
|
|
589
|
-
return attDataBase64;
|
|
615
|
+
export function getSeenAttDataKeyFromGossipAttestation(attestation) {
|
|
616
|
+
// SeenAttDataKey is the same as gossip index
|
|
617
|
+
return attestation.attDataBase64;
|
|
590
618
|
}
|
|
591
619
|
/**
|
|
592
620
|
* Extract attestation data key from SignedAggregateAndProof Uint8Array to use cached data from SeenAttestationDatas
|
|
593
|
-
* - for pre-electra, it's the AttestationData base64
|
|
594
|
-
* -
|
|
621
|
+
* - for both electra + pre-electra, it's the AttestationData base64
|
|
622
|
+
* - consumers need to also pass slot + committeeIndex to get the correct SeenAttestationData
|
|
595
623
|
*/
|
|
596
624
|
export function getSeenAttDataKeyFromSignedAggregateAndProof(fork, aggregateAndProof) {
|
|
625
|
+
return isForkPostElectra(fork)
|
|
626
|
+
? getAttDataFromSignedAggregateAndProofElectra(aggregateAndProof)
|
|
627
|
+
: getAttDataFromSignedAggregateAndProofPhase0(aggregateAndProof);
|
|
628
|
+
}
|
|
629
|
+
export function getCommitteeIndexFromAttestationOrBytes(fork, attestationOrBytes) {
|
|
630
|
+
const isGossipAttestation = attestationOrBytes.serializedData !== null;
|
|
597
631
|
if (isForkPostElectra(fork)) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
632
|
+
if (isGossipAttestation) {
|
|
633
|
+
return getCommitteeIndexFromSingleAttestationSerialized(ForkName.electra, attestationOrBytes.serializedData);
|
|
634
|
+
}
|
|
635
|
+
return attestationOrBytes.attestation.committeeIndex;
|
|
636
|
+
}
|
|
637
|
+
if (isGossipAttestation) {
|
|
638
|
+
return getCommitteeIndexFromSingleAttestationSerialized(ForkName.phase0, attestationOrBytes.serializedData);
|
|
601
639
|
}
|
|
602
|
-
|
|
603
|
-
|
|
640
|
+
return attestationOrBytes.attestation.data.index;
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Convert pre-electra single attestation (`phase0.Attestation`) to post-electra `SingleAttestation`
|
|
644
|
+
*/
|
|
645
|
+
export function toElectraSingleAttestation(attestation, attesterIndex) {
|
|
646
|
+
return {
|
|
647
|
+
committeeIndex: attestation.data.index,
|
|
648
|
+
attesterIndex,
|
|
649
|
+
data: attestation.data,
|
|
650
|
+
signature: attestation.signature,
|
|
651
|
+
};
|
|
604
652
|
}
|
|
605
653
|
//# sourceMappingURL=attestation.js.map
|