@lodestar/beacon-node 1.45.0-dev.9d930bdc5b → 1.45.0-dev.aadf7a7167
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/index.d.ts +1 -1
- package/lib/api/impl/beacon/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/index.js.map +1 -1
- package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +6 -43
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/beacon/state/index.d.ts +1 -1
- package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/index.js +48 -5
- package/lib/api/impl/beacon/state/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +13 -3
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +48 -4
- package/lib/api/impl/beacon/state/utils.js.map +1 -1
- package/lib/api/impl/debug/index.d.ts +1 -1
- package/lib/api/impl/debug/index.d.ts.map +1 -1
- package/lib/api/impl/debug/index.js +2 -2
- package/lib/api/impl/debug/index.js.map +1 -1
- package/lib/api/impl/lodestar/index.js +2 -2
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/proof/index.d.ts +1 -1
- package/lib/api/impl/proof/index.d.ts.map +1 -1
- package/lib/api/impl/proof/index.js +2 -2
- package/lib/api/impl/proof/index.js.map +1 -1
- package/lib/api/impl/utils.d.ts +23 -0
- package/lib/api/impl/utils.d.ts.map +1 -1
- package/lib/api/impl/utils.js +44 -1
- package/lib/api/impl/utils.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts +0 -14
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +67 -62
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/api/rest/base.d.ts.map +1 -1
- package/lib/api/rest/base.js +8 -0
- package/lib/api/rest/base.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +2 -5
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
- package/lib/chain/builderCircuitBreaker.d.ts +31 -0
- package/lib/chain/builderCircuitBreaker.d.ts.map +1 -0
- package/lib/chain/builderCircuitBreaker.js +59 -0
- package/lib/chain/builderCircuitBreaker.js.map +1 -0
- package/lib/chain/chain.d.ts +3 -2
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +4 -3
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +7 -0
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +2 -0
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.d.ts +11 -0
- package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadEnvelope.js +2 -0
- package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/interface.d.ts +3 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +11 -6
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/lightClient/proofs.d.ts.map +1 -1
- package/lib/chain/lightClient/proofs.js +28 -2
- package/lib/chain/lightClient/proofs.js.map +1 -1
- package/lib/chain/lightClient/types.d.ts +3 -1
- package/lib/chain/lightClient/types.d.ts.map +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
- package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts +2 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.js +3 -0
- package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -1
- package/lib/chain/options.d.ts +5 -0
- package/lib/chain/options.d.ts.map +1 -1
- package/lib/chain/options.js +1 -0
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +12 -7
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +4 -12
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/seenCache/index.d.ts +0 -1
- package/lib/chain/seenCache/index.d.ts.map +1 -1
- package/lib/chain/seenCache/index.js +0 -1
- package/lib/chain/seenCache/index.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +3 -2
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +52 -1
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +11 -10
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +30 -0
- package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
- package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/validation/proposerPreferences.js +14 -5
- package/lib/chain/validation/proposerPreferences.js.map +1 -1
- package/lib/chain/validation/signatureSets/aggregateAndProof.d.ts.map +1 -1
- package/lib/chain/validation/signatureSets/aggregateAndProof.js +2 -3
- package/lib/chain/validation/signatureSets/aggregateAndProof.js.map +1 -1
- package/lib/db/repositories/lightclientSyncCommitteeWitness.d.ts.map +1 -1
- package/lib/db/repositories/lightclientSyncCommitteeWitness.js +42 -7
- package/lib/db/repositories/lightclientSyncCommitteeWitness.js.map +1 -1
- package/lib/execution/builder/http.d.ts +18 -0
- package/lib/execution/builder/http.d.ts.map +1 -1
- package/lib/execution/builder/http.js +20 -11
- package/lib/execution/builder/http.js.map +1 -1
- package/lib/metrics/metrics/beacon.d.ts +6 -0
- package/lib/metrics/metrics/beacon.d.ts.map +1 -1
- package/lib/metrics/metrics/beacon.js +18 -0
- package/lib/metrics/metrics/beacon.js.map +1 -1
- package/lib/network/core/metrics.d.ts +65 -0
- package/lib/network/core/metrics.d.ts.map +1 -1
- package/lib/network/core/metrics.js +94 -0
- package/lib/network/core/metrics.js.map +1 -1
- package/lib/network/discv5/utils.d.ts.map +1 -1
- package/lib/network/discv5/utils.js +12 -3
- package/lib/network/discv5/utils.js.map +1 -1
- package/lib/network/gossip/encoding.d.ts +2 -2
- package/lib/network/gossip/encoding.d.ts.map +1 -1
- package/lib/network/gossip/encoding.js +22 -9
- package/lib/network/gossip/encoding.js.map +1 -1
- package/lib/network/gossip/gossipsub.d.ts.map +1 -1
- package/lib/network/gossip/gossipsub.js +4 -3
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +831 -226
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +47 -4
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/peers/peerManager.d.ts.map +1 -1
- package/lib/network/peers/peerManager.js +10 -0
- package/lib/network/peers/peerManager.js.map +1 -1
- package/lib/network/peers/score/score.d.ts +3 -1
- package/lib/network/peers/score/score.d.ts.map +1 -1
- package/lib/network/peers/score/score.js +6 -1
- package/lib/network/peers/score/score.js.map +1 -1
- package/lib/network/peers/score/store.d.ts.map +1 -1
- package/lib/network/peers/score/store.js +6 -1
- package/lib/network/peers/score/store.js.map +1 -1
- package/lib/network/peers/utils/prioritizePeers.d.ts.map +1 -1
- package/lib/network/peers/utils/prioritizePeers.js +14 -0
- package/lib/network/peers/utils/prioritizePeers.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +6 -3
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/sync/range/chain.d.ts +4 -1
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +3 -3
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +10 -0
- package/lib/sync/range/range.js.map +1 -1
- package/lib/util/graffiti.d.ts +15 -0
- package/lib/util/graffiti.d.ts.map +1 -1
- package/lib/util/graffiti.js +55 -0
- package/lib/util/graffiti.js.map +1 -1
- package/package.json +19 -19
- package/src/api/impl/beacon/index.ts +1 -1
- package/src/api/impl/beacon/pool/index.ts +5 -53
- package/src/api/impl/beacon/state/index.ts +55 -3
- package/src/api/impl/beacon/state/utils.ts +68 -4
- package/src/api/impl/debug/index.ts +3 -2
- package/src/api/impl/lodestar/index.ts +2 -2
- package/src/api/impl/proof/index.ts +2 -2
- package/src/api/impl/utils.ts +51 -1
- package/src/api/impl/validator/index.ts +75 -67
- package/src/api/rest/base.ts +9 -0
- package/src/chain/blocks/importBlock.ts +2 -7
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +2 -2
- package/src/chain/builderCircuitBreaker.ts +84 -0
- package/src/chain/chain.ts +7 -3
- package/src/chain/errors/blockError.ts +3 -0
- package/src/chain/errors/executionPayloadEnvelope.ts +9 -0
- package/src/chain/interface.ts +2 -2
- package/src/chain/lightClient/index.ts +12 -7
- package/src/chain/lightClient/proofs.ts +36 -1
- package/src/chain/lightClient/types.ts +3 -1
- package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
- package/src/chain/opPools/proposerPreferencesPool.ts +5 -1
- package/src/chain/options.ts +6 -0
- package/src/chain/prepareNextSlot.ts +11 -7
- package/src/chain/produceBlock/produceBlockBody.ts +9 -17
- package/src/chain/seenCache/index.ts +0 -1
- package/src/chain/stateCache/persistentCheckpointsCache.ts +3 -2
- package/src/chain/validation/block.ts +69 -1
- package/src/chain/validation/executionPayloadBid.ts +14 -9
- package/src/chain/validation/executionPayloadEnvelope.ts +39 -0
- package/src/chain/validation/proposerPreferences.ts +15 -5
- package/src/chain/validation/signatureSets/aggregateAndProof.ts +3 -3
- package/src/db/repositories/lightclientSyncCommitteeWitness.ts +57 -9
- package/src/execution/builder/http.ts +30 -17
- package/src/metrics/metrics/beacon.ts +19 -0
- package/src/network/core/metrics.ts +94 -0
- package/src/network/discv5/utils.ts +11 -3
- package/src/network/gossip/encoding.ts +20 -7
- package/src/network/gossip/gossipsub.ts +9 -3
- package/src/network/gossip/topic.ts +59 -4
- package/src/network/peers/peerManager.ts +11 -0
- package/src/network/peers/score/score.ts +8 -1
- package/src/network/peers/score/store.ts +8 -1
- package/src/network/peers/utils/prioritizePeers.ts +15 -0
- package/src/network/processor/gossipHandlers.ts +6 -2
- package/src/sync/range/chain.ts +4 -5
- package/src/sync/range/range.ts +10 -0
- package/src/util/graffiti.ts +78 -0
- package/lib/chain/seenCache/seenProposerPreferences.d.ts +0 -16
- package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +0 -1
- package/lib/chain/seenCache/seenProposerPreferences.js +0 -26
- package/lib/chain/seenCache/seenProposerPreferences.js.map +0 -1
- package/src/chain/seenCache/seenProposerPreferences.ts +0 -32
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import {Tree} from "@chainsafe/persistent-merkle-tree";
|
|
2
2
|
import {
|
|
3
3
|
BLOCK_BODY_EXECUTION_PAYLOAD_GINDEX,
|
|
4
|
+
CURRENT_SYNC_COMMITTEE_GINDEX_GLOAS,
|
|
4
5
|
FINALIZED_ROOT_GINDEX,
|
|
5
6
|
FINALIZED_ROOT_GINDEX_ELECTRA,
|
|
7
|
+
FINALIZED_ROOT_GINDEX_GLOAS,
|
|
6
8
|
ForkName,
|
|
7
9
|
ForkPostBellatrix,
|
|
10
|
+
NEXT_SYNC_COMMITTEE_GINDEX_GLOAS,
|
|
8
11
|
isForkPostElectra,
|
|
12
|
+
isForkPostGloas,
|
|
9
13
|
} from "@lodestar/params";
|
|
10
14
|
import {BeaconStateAllForks, CachedBeaconStateAllForks} from "@lodestar/state-transition";
|
|
11
15
|
import {BeaconBlockBody, SSZTypesFor, ssz} from "@lodestar/types";
|
|
@@ -17,6 +21,24 @@ export function getSyncCommitteesWitness(fork: ForkName, state: BeaconStateAllFo
|
|
|
17
21
|
let currentSyncCommitteeRoot: Uint8Array;
|
|
18
22
|
let nextSyncCommitteeRoot: Uint8Array;
|
|
19
23
|
|
|
24
|
+
if (isForkPostGloas(fork)) {
|
|
25
|
+
const tree = new Tree(state.node);
|
|
26
|
+
const currentSyncCommitteeGindex = BigInt(CURRENT_SYNC_COMMITTEE_GINDEX_GLOAS);
|
|
27
|
+
const nextSyncCommitteeGindex = BigInt(NEXT_SYNC_COMMITTEE_GINDEX_GLOAS);
|
|
28
|
+
|
|
29
|
+
currentSyncCommitteeRoot = tree.getRoot(currentSyncCommitteeGindex);
|
|
30
|
+
nextSyncCommitteeRoot = tree.getRoot(nextSyncCommitteeGindex);
|
|
31
|
+
witness = [];
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
witness,
|
|
35
|
+
currentSyncCommitteeRoot,
|
|
36
|
+
nextSyncCommitteeRoot,
|
|
37
|
+
currentSyncCommitteeBranch: tree.getSingleProof(currentSyncCommitteeGindex),
|
|
38
|
+
nextSyncCommitteeBranch: tree.getSingleProof(nextSyncCommitteeGindex),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
20
42
|
if (isForkPostElectra(fork)) {
|
|
21
43
|
const n2 = n1.left;
|
|
22
44
|
const n5 = n2.right;
|
|
@@ -60,17 +82,30 @@ export function getSyncCommitteesWitness(fork: ForkName, state: BeaconStateAllFo
|
|
|
60
82
|
}
|
|
61
83
|
|
|
62
84
|
export function getNextSyncCommitteeBranch(syncCommitteesWitness: SyncCommitteeWitness): Uint8Array[] {
|
|
85
|
+
if (syncCommitteesWitness.nextSyncCommitteeBranch) {
|
|
86
|
+
return syncCommitteesWitness.nextSyncCommitteeBranch;
|
|
87
|
+
}
|
|
88
|
+
|
|
63
89
|
// Witness branch is sorted by descending gindex
|
|
64
90
|
return [syncCommitteesWitness.currentSyncCommitteeRoot, ...syncCommitteesWitness.witness];
|
|
65
91
|
}
|
|
66
92
|
|
|
67
93
|
export function getCurrentSyncCommitteeBranch(syncCommitteesWitness: SyncCommitteeWitness): Uint8Array[] {
|
|
94
|
+
if (syncCommitteesWitness.currentSyncCommitteeBranch) {
|
|
95
|
+
return syncCommitteesWitness.currentSyncCommitteeBranch;
|
|
96
|
+
}
|
|
97
|
+
|
|
68
98
|
// Witness branch is sorted by descending gindex
|
|
69
99
|
return [syncCommitteesWitness.nextSyncCommitteeRoot, ...syncCommitteesWitness.witness];
|
|
70
100
|
}
|
|
71
101
|
|
|
72
102
|
export function getFinalizedRootProof(state: CachedBeaconStateAllForks): Uint8Array[] {
|
|
73
|
-
const
|
|
103
|
+
const fork = state.config.getForkName(state.slot);
|
|
104
|
+
const finalizedRootGindex = isForkPostGloas(fork)
|
|
105
|
+
? FINALIZED_ROOT_GINDEX_GLOAS
|
|
106
|
+
: state.epochCtx.isPostElectra()
|
|
107
|
+
? FINALIZED_ROOT_GINDEX_ELECTRA
|
|
108
|
+
: FINALIZED_ROOT_GINDEX;
|
|
74
109
|
return new Tree(state.node).getSingleProof(BigInt(finalizedRootGindex));
|
|
75
110
|
}
|
|
76
111
|
|
|
@@ -26,8 +26,10 @@
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
export type SyncCommitteeWitness = {
|
|
29
|
-
/**
|
|
29
|
+
/** Shared witness for pre-Gloas forks where current and next sync committees are siblings. */
|
|
30
30
|
witness: Uint8Array[];
|
|
31
31
|
currentSyncCommitteeRoot: Uint8Array;
|
|
32
32
|
nextSyncCommitteeRoot: Uint8Array;
|
|
33
|
+
currentSyncCommitteeBranch?: Uint8Array[];
|
|
34
|
+
nextSyncCommitteeBranch?: Uint8Array[];
|
|
33
35
|
};
|
|
@@ -355,7 +355,7 @@ export class AggregatedAttestationPool {
|
|
|
355
355
|
// after all committees are processed, we have a list of sameAttDataCons
|
|
356
356
|
for (const consolidation of sameAttDataCons) {
|
|
357
357
|
// Score attestations by profitability to maximize proposer reward
|
|
358
|
-
const flags = getAttestationParticipationStatus(
|
|
358
|
+
const {flags} = getAttestationParticipationStatus(
|
|
359
359
|
ForkSeq[fork],
|
|
360
360
|
consolidation.attData,
|
|
361
361
|
inclusionDistance,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {RootHex, Slot, gloas} from "@lodestar/types";
|
|
1
|
+
import {RootHex, Slot, ValidatorIndex, gloas} from "@lodestar/types";
|
|
2
2
|
import {toRootHex} from "@lodestar/utils";
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -22,6 +22,10 @@ export class ProposerPreferencesPool {
|
|
|
22
22
|
return this.bySlot.get(slot)?.get(dependentRootHex) ?? null;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
isKnown(proposalSlot: Slot, dependentRoot: RootHex, validatorIndex: ValidatorIndex): boolean {
|
|
26
|
+
return this.get(proposalSlot, dependentRoot)?.message.validatorIndex === validatorIndex;
|
|
27
|
+
}
|
|
28
|
+
|
|
25
29
|
add(signed: gloas.SignedProposerPreferences): void {
|
|
26
30
|
const {proposalSlot, dependentRoot} = signed.message;
|
|
27
31
|
const rootHex = toRootHex(dependentRoot);
|
package/src/chain/options.ts
CHANGED
|
@@ -35,6 +35,7 @@ export type IChainOptions = BlockProcessOpts &
|
|
|
35
35
|
persistOrphanedBlocksDir?: string;
|
|
36
36
|
skipCreateStateCacheIfAvailable?: boolean;
|
|
37
37
|
suggestedFeeRecipient: string;
|
|
38
|
+
graffitiAppend?: boolean;
|
|
38
39
|
maxSkipSlots?: number;
|
|
39
40
|
/** Ensure blobs returned by the execution engine are valid */
|
|
40
41
|
sanityCheckExecutionEngineBlobs?: boolean;
|
|
@@ -48,6 +49,10 @@ export type IChainOptions = BlockProcessOpts &
|
|
|
48
49
|
archiveDateEpochs?: number;
|
|
49
50
|
nHistoricalStatesFileDataStore?: boolean;
|
|
50
51
|
nativeStateView?: boolean;
|
|
52
|
+
/** Builder circuit breaker fault inspection window in slots */
|
|
53
|
+
faultInspectionWindow?: number;
|
|
54
|
+
/** Allowed unrevealed payloads within the fault inspection window */
|
|
55
|
+
allowedFaults?: number;
|
|
51
56
|
};
|
|
52
57
|
|
|
53
58
|
export type BlockProcessOpts = {
|
|
@@ -107,6 +112,7 @@ export const defaultChainOptions: IChainOptions = {
|
|
|
107
112
|
computeUnrealized: true,
|
|
108
113
|
fastConfirmation: false,
|
|
109
114
|
suggestedFeeRecipient: defaultValidatorOptions.suggestedFeeRecipient,
|
|
115
|
+
graffitiAppend: true,
|
|
110
116
|
serveHistoricalState: false,
|
|
111
117
|
assertCorrectProgressiveBalances: false,
|
|
112
118
|
archiveStateEpochFrequency: 1024,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
3
|
import {getSafeExecutionBlockHash} from "@lodestar/fork-choice";
|
|
4
|
-
import {ForkPostBellatrix, ForkSeq, SLOTS_PER_EPOCH, isForkPostBellatrix} from "@lodestar/params";
|
|
4
|
+
import {ForkPostBellatrix, ForkSeq, SLOTS_PER_EPOCH, isForkPostBellatrix, isForkPostGloas} from "@lodestar/params";
|
|
5
5
|
import {
|
|
6
6
|
IBeaconStateView,
|
|
7
7
|
IBeaconStateViewBellatrix,
|
|
@@ -152,12 +152,16 @@ export class PrepareNextSlotScheduler {
|
|
|
152
152
|
updatedHead = proposerHead;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
155
|
+
if (isForkPostGloas(fork)) {
|
|
156
|
+
this.chain.builderCircuitBreaker.update(clockSlot);
|
|
157
|
+
} else {
|
|
158
|
+
// Update the builder status, if enabled shoot an api call to check status
|
|
159
|
+
this.chain.updateBuilderStatus(clockSlot);
|
|
160
|
+
if (this.chain.executionBuilder?.status === BuilderStatus.enabled) {
|
|
161
|
+
this.chain.executionBuilder.checkStatus().catch((e) => {
|
|
162
|
+
this.logger.error("Builder disabled as the check status api failed", {prepareSlot}, e as Error);
|
|
163
|
+
});
|
|
164
|
+
}
|
|
161
165
|
}
|
|
162
166
|
}
|
|
163
167
|
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
ValidatorIndex,
|
|
44
44
|
Wei,
|
|
45
45
|
altair,
|
|
46
|
+
bellatrix,
|
|
46
47
|
capella,
|
|
47
48
|
deneb,
|
|
48
49
|
electra,
|
|
@@ -830,28 +831,19 @@ export function getPayloadAttributesForSSE(
|
|
|
830
831
|
feeRecipient,
|
|
831
832
|
});
|
|
832
833
|
|
|
833
|
-
|
|
834
|
-
if (isForkPostGloas(fork)) {
|
|
835
|
-
const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(
|
|
836
|
-
toRootHex(parentBlockRoot),
|
|
837
|
-
toRootHex(parentBlockHash)
|
|
838
|
-
);
|
|
839
|
-
if (parentBlock?.executionPayloadBlockHash == null) {
|
|
840
|
-
throw Error(`Parent block not found in fork choice root=${toRootHex(parentBlockRoot)}`);
|
|
841
|
-
}
|
|
842
|
-
parentBlockNumber = parentBlock.executionPayloadNumber;
|
|
843
|
-
} else {
|
|
844
|
-
parentBlockNumber = prepareState.payloadBlockNumber;
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
const ssePayloadAttributes: SSEPayloadAttributes = {
|
|
834
|
+
const ssePayloadAttributes = {
|
|
848
835
|
proposerIndex: prepareState.getBeaconProposer(prepareSlot),
|
|
849
836
|
proposalSlot: prepareSlot,
|
|
850
|
-
parentBlockNumber,
|
|
851
837
|
parentBlockRoot,
|
|
852
838
|
parentBlockHash,
|
|
853
839
|
payloadAttributes,
|
|
854
|
-
};
|
|
840
|
+
} as SSEPayloadAttributes;
|
|
841
|
+
|
|
842
|
+
if (!isForkPostGloas(fork)) {
|
|
843
|
+
// Removed in Gloas, builders can get the block number from the EL via the block hash if required
|
|
844
|
+
(ssePayloadAttributes as bellatrix.SSEPayloadAttributes).parentBlockNumber = prepareState.payloadBlockNumber;
|
|
845
|
+
}
|
|
846
|
+
|
|
855
847
|
return ssePayloadAttributes;
|
|
856
848
|
}
|
|
857
849
|
|
|
@@ -5,4 +5,3 @@ export {SeenContributionAndProof} from "./seenCommitteeContribution.js";
|
|
|
5
5
|
export {SeenExecutionPayloadBids} from "./seenExecutionPayloadBids.js";
|
|
6
6
|
export {SeenBlockInput} from "./seenGossipBlockInput.js";
|
|
7
7
|
export {PayloadEnvelopeInput, SeenPayloadEnvelopeInput} from "./seenPayloadEnvelopeInput.js";
|
|
8
|
-
export {SeenProposerPreferences} from "./seenProposerPreferences.js";
|
|
@@ -331,8 +331,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
|
|
|
331
331
|
const key = toCacheKey(cpHex);
|
|
332
332
|
const cacheItem = this.cache.get(key);
|
|
333
333
|
this.metrics?.cpStateCache.adds.inc();
|
|
334
|
-
|
|
335
|
-
|
|
334
|
+
// keep an existing persistedKey (persisted or reloaded-in-memory); dropping it orphans the on-disk file
|
|
335
|
+
const persistedKey = cacheItem && (isPersistedCacheItem(cacheItem) ? cacheItem.value : cacheItem.persistedKey);
|
|
336
|
+
if (persistedKey !== undefined) {
|
|
336
337
|
// was persisted to disk, set back to memory
|
|
337
338
|
this.cache.set(key, {type: CacheItemType.inMemory, state, persistedKey});
|
|
338
339
|
this.logger.verbose("Added checkpoint state to memory but a persisted key existed", {
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
2
|
import {ExecutionStatus} from "@lodestar/fork-choice";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ForkName,
|
|
5
|
+
MAX_ATTESTATIONS_ELECTRA,
|
|
6
|
+
MAX_ATTESTER_SLASHINGS_ELECTRA,
|
|
7
|
+
MAX_BLS_TO_EXECUTION_CHANGES,
|
|
8
|
+
MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
|
|
9
|
+
MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD,
|
|
10
|
+
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
|
|
11
|
+
MAX_DEPOSIT_REQUESTS_PER_PAYLOAD,
|
|
12
|
+
MAX_PAYLOAD_ATTESTATIONS,
|
|
13
|
+
MAX_PROPOSER_SLASHINGS,
|
|
14
|
+
MAX_VOLUNTARY_EXITS,
|
|
15
|
+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
|
|
16
|
+
isForkPostBellatrix,
|
|
17
|
+
isForkPostDeneb,
|
|
18
|
+
isForkPostGloas,
|
|
19
|
+
} from "@lodestar/params";
|
|
4
20
|
import {
|
|
5
21
|
computeEpochAtSlot,
|
|
6
22
|
computeStartSlotAtEpoch,
|
|
@@ -164,6 +180,58 @@ export async function validateGossipBlock(
|
|
|
164
180
|
});
|
|
165
181
|
}
|
|
166
182
|
|
|
183
|
+
// [REJECT] The counts of `block.body.parent_execution_requests` are within
|
|
184
|
+
// their respective limits -- i.e. validate that
|
|
185
|
+
// `len(block.body.parent_execution_requests.deposits) <= MAX_DEPOSIT_REQUESTS_PER_PAYLOAD`,
|
|
186
|
+
// `len(block.body.parent_execution_requests.withdrawals) <= MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD`,
|
|
187
|
+
// `len(block.body.parent_execution_requests.consolidations) <= MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD`,
|
|
188
|
+
// `len(block.body.parent_execution_requests.builder_deposits) <= MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD`,
|
|
189
|
+
// and
|
|
190
|
+
// `len(block.body.parent_execution_requests.builder_exits) <= MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD`.
|
|
191
|
+
// [REJECT] The counts of the block body operations are within their respective
|
|
192
|
+
// limits -- i.e. validate that
|
|
193
|
+
// `len(block.body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS`,
|
|
194
|
+
// `len(block.body.attester_slashings) <= MAX_ATTESTER_SLASHINGS_ELECTRA`,
|
|
195
|
+
// `len(block.body.attestations) <= MAX_ATTESTATIONS_ELECTRA`,
|
|
196
|
+
// `len(block.body.deposits) == 0`,
|
|
197
|
+
// `len(block.body.voluntary_exits) <= MAX_VOLUNTARY_EXITS`,
|
|
198
|
+
// `len(block.body.bls_to_execution_changes) <= MAX_BLS_TO_EXECUTION_CHANGES`,
|
|
199
|
+
// and `len(block.body.payload_attestations) <= MAX_PAYLOAD_ATTESTATIONS`.
|
|
200
|
+
const body = (block as gloas.BeaconBlock).body;
|
|
201
|
+
const requests = body.parentExecutionRequests;
|
|
202
|
+
const countLimits: [string, number, number][] = [
|
|
203
|
+
["parentExecutionRequests.deposits", requests.deposits.length, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD],
|
|
204
|
+
["parentExecutionRequests.withdrawals", requests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD],
|
|
205
|
+
[
|
|
206
|
+
"parentExecutionRequests.consolidations",
|
|
207
|
+
requests.consolidations.length,
|
|
208
|
+
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
|
|
209
|
+
],
|
|
210
|
+
[
|
|
211
|
+
"parentExecutionRequests.builderDeposits",
|
|
212
|
+
requests.builderDeposits.length,
|
|
213
|
+
MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
|
|
214
|
+
],
|
|
215
|
+
["parentExecutionRequests.builderExits", requests.builderExits.length, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD],
|
|
216
|
+
["proposerSlashings", body.proposerSlashings.length, MAX_PROPOSER_SLASHINGS],
|
|
217
|
+
["attesterSlashings", body.attesterSlashings.length, MAX_ATTESTER_SLASHINGS_ELECTRA],
|
|
218
|
+
["attestations", body.attestations.length, MAX_ATTESTATIONS_ELECTRA],
|
|
219
|
+
["deposits", body.deposits.length, 0],
|
|
220
|
+
["voluntaryExits", body.voluntaryExits.length, MAX_VOLUNTARY_EXITS],
|
|
221
|
+
["blsToExecutionChanges", body.blsToExecutionChanges.length, MAX_BLS_TO_EXECUTION_CHANGES],
|
|
222
|
+
["payloadAttestations", body.payloadAttestations.length, MAX_PAYLOAD_ATTESTATIONS],
|
|
223
|
+
];
|
|
224
|
+
for (const [name, count, limit] of countLimits) {
|
|
225
|
+
if (count > limit) {
|
|
226
|
+
throw new BlockGossipError(GossipAction.REJECT, {
|
|
227
|
+
code: BlockErrorCode.TOO_MANY_BLOCK_OPERATIONS,
|
|
228
|
+
name,
|
|
229
|
+
count,
|
|
230
|
+
limit,
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
167
235
|
// TODO GLOAS: [REJECT] The block's execution payload parent (defined by bid.parent_block_hash) passes all validation
|
|
168
236
|
// This requires execution engine integration to verify the parent block hash
|
|
169
237
|
}
|
|
@@ -37,9 +37,11 @@ async function validateExecutionPayloadBid(
|
|
|
37
37
|
const parentBlockRootHex = toRootHex(bid.parentBlockRoot);
|
|
38
38
|
const parentBlockHashHex = toRootHex(bid.parentBlockHash);
|
|
39
39
|
|
|
40
|
-
// [IGNORE] `bid.slot` is the current slot or the next slot.
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
// [IGNORE] `bid.slot` is the current slot, or the next slot (`bid.slot - 1` is current), allowing for `MAXIMUM_GOSSIP_CLOCK_DISPARITY`.
|
|
41
|
+
if (
|
|
42
|
+
!chain.clock.isCurrentSlotGivenGossipDisparity(bid.slot) &&
|
|
43
|
+
!chain.clock.isCurrentSlotGivenGossipDisparity(bid.slot - 1)
|
|
44
|
+
) {
|
|
43
45
|
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
44
46
|
code: ExecutionPayloadBidErrorCode.INVALID_SLOT,
|
|
45
47
|
builderIndex: bid.builderIndex,
|
|
@@ -122,17 +124,20 @@ async function validateExecutionPayloadBid(
|
|
|
122
124
|
throw new Error(`Expected gloas+ state for execution payload bid validation, got fork=${state.forkName}`);
|
|
123
125
|
}
|
|
124
126
|
|
|
125
|
-
// [REJECT] `bid.builder_index` is
|
|
126
|
-
// `
|
|
127
|
-
|
|
128
|
-
try
|
|
129
|
-
|
|
130
|
-
} catch {
|
|
127
|
+
// [REJECT] `bid.builder_index` is within bounds -- i.e. `bid.builder_index < len(state.builders)`.
|
|
128
|
+
// `state.getBuilder` returns a lazy SSZ `getReadonly` view that is not bounds-checked eagerly; an
|
|
129
|
+
// out-of-range index only throws (`LeafNode has no right node`) on deferred field access (e.g. inside
|
|
130
|
+
// `isActiveBuilder`), escaping a try/catch around `getBuilder`. Check the length explicitly instead.
|
|
131
|
+
if (bid.builderIndex >= state.getBuildersLength()) {
|
|
131
132
|
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
132
133
|
code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE,
|
|
133
134
|
builderIndex: bid.builderIndex,
|
|
134
135
|
});
|
|
135
136
|
}
|
|
137
|
+
|
|
138
|
+
// [REJECT] `bid.builder_index` is a valid/active builder index -- i.e.
|
|
139
|
+
// `is_active_builder(state, bid.builder_index)` returns `True`.
|
|
140
|
+
const builder = state.getBuilder(bid.builderIndex);
|
|
136
141
|
if (!isActiveBuilder(builder, state.finalizedCheckpoint.epoch)) {
|
|
137
142
|
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
138
143
|
code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE,
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import {PayloadStatus} from "@lodestar/fork-choice";
|
|
2
|
+
import {
|
|
3
|
+
MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
|
|
4
|
+
MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD,
|
|
5
|
+
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
|
|
6
|
+
MAX_DEPOSIT_REQUESTS_PER_PAYLOAD,
|
|
7
|
+
MAX_WITHDRAWALS_PER_PAYLOAD,
|
|
8
|
+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
|
|
9
|
+
} from "@lodestar/params";
|
|
2
10
|
import {
|
|
3
11
|
computeStartSlotAtEpoch,
|
|
4
12
|
getExecutionPayloadEnvelopeSignatureSet,
|
|
@@ -115,6 +123,37 @@ async function validateExecutionPayloadEnvelope(
|
|
|
115
123
|
});
|
|
116
124
|
}
|
|
117
125
|
|
|
126
|
+
// [REJECT] The counts of `execution_requests` are within their respective limits.
|
|
127
|
+
// New in Gloas:EIP7688 — progressive lists are unbounded at the type level, so bounds
|
|
128
|
+
// are enforced here in gossip validation.
|
|
129
|
+
const {executionRequests} = envelope;
|
|
130
|
+
const requestCountLimits: [string, number, number][] = [
|
|
131
|
+
["deposits", executionRequests.deposits.length, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD],
|
|
132
|
+
["withdrawals", executionRequests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD],
|
|
133
|
+
["consolidations", executionRequests.consolidations.length, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD],
|
|
134
|
+
["builderDeposits", executionRequests.builderDeposits.length, MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD],
|
|
135
|
+
["builderExits", executionRequests.builderExits.length, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD],
|
|
136
|
+
];
|
|
137
|
+
for (const [name, count, limit] of requestCountLimits) {
|
|
138
|
+
if (count > limit) {
|
|
139
|
+
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
140
|
+
code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_COUNT_EXCEEDED,
|
|
141
|
+
name,
|
|
142
|
+
count,
|
|
143
|
+
limit,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// [REJECT] The number of withdrawals is within the limit.
|
|
149
|
+
if (payload.withdrawals.length > MAX_WITHDRAWALS_PER_PAYLOAD) {
|
|
150
|
+
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
151
|
+
code: ExecutionPayloadEnvelopeErrorCode.WITHDRAWALS_COUNT_EXCEEDED,
|
|
152
|
+
count: payload.withdrawals.length,
|
|
153
|
+
limit: MAX_WITHDRAWALS_PER_PAYLOAD,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
118
157
|
// Get the block state to verify the builder's signature.
|
|
119
158
|
const blockState = await chain.regen
|
|
120
159
|
.getState(block.stateRoot, RegenCaller.validateGossipPayloadEnvelope)
|
|
@@ -32,8 +32,9 @@ export async function validateGossipProposerPreferences(
|
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
// [IGNORE] `preferences.proposal_slot` has not already passed.
|
|
36
|
-
|
|
35
|
+
// [IGNORE] `preferences.proposal_slot` has not already passed, i.e. `proposal_slot > current_slot`,
|
|
36
|
+
// allowing for `MAXIMUM_GOSSIP_CLOCK_DISPARITY`.
|
|
37
|
+
const currentSlot = chain.clock.currentSlotWithGossipDisparity;
|
|
37
38
|
if (proposalSlot <= currentSlot) {
|
|
38
39
|
throw new ProposerPreferencesError(GossipAction.IGNORE, {
|
|
39
40
|
code: ProposerPreferencesErrorCode.PROPOSAL_SLOT_PASSED,
|
|
@@ -81,7 +82,7 @@ export async function validateGossipProposerPreferences(
|
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
// [IGNORE] First valid message for (dependent_root, proposal_slot, validator_index).
|
|
84
|
-
if (chain.
|
|
85
|
+
if (chain.proposerPreferencesPool.isKnown(proposalSlot, dependentRootHex, validatorIndex)) {
|
|
85
86
|
throw new ProposerPreferencesError(GossipAction.IGNORE, {
|
|
86
87
|
code: ProposerPreferencesErrorCode.ALREADY_KNOWN,
|
|
87
88
|
proposalSlot,
|
|
@@ -105,6 +106,15 @@ export async function validateGossipProposerPreferences(
|
|
|
105
106
|
});
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
//
|
|
109
|
-
chain.
|
|
109
|
+
// Repeated check - deals with race-condition between preferences submissions
|
|
110
|
+
if (chain.proposerPreferencesPool.isKnown(proposalSlot, dependentRootHex, validatorIndex)) {
|
|
111
|
+
throw new ProposerPreferencesError(GossipAction.IGNORE, {
|
|
112
|
+
code: ProposerPreferencesErrorCode.ALREADY_KNOWN,
|
|
113
|
+
proposalSlot,
|
|
114
|
+
validatorIndex,
|
|
115
|
+
dependentRoot: dependentRootHex,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
chain.proposerPreferencesPool.add(signedProposerPreferences);
|
|
110
120
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {BeaconConfig} from "@lodestar/config";
|
|
2
|
-
import {DOMAIN_AGGREGATE_AND_PROOF
|
|
2
|
+
import {DOMAIN_AGGREGATE_AND_PROOF} from "@lodestar/params";
|
|
3
3
|
import {ISignatureSet, SignatureSetType, computeSigningRoot, computeStartSlotAtEpoch} from "@lodestar/state-transition";
|
|
4
|
-
import {Epoch, SignedAggregateAndProof, ValidatorIndex
|
|
4
|
+
import {Epoch, SignedAggregateAndProof, ValidatorIndex} from "@lodestar/types";
|
|
5
5
|
|
|
6
6
|
export function getAggregateAndProofSigningRoot(
|
|
7
7
|
config: BeaconConfig,
|
|
@@ -14,7 +14,7 @@ export function getAggregateAndProofSigningRoot(
|
|
|
14
14
|
const slot = computeStartSlotAtEpoch(epoch);
|
|
15
15
|
const fork = config.getForkName(slot);
|
|
16
16
|
const aggregatorDomain = config.getDomainAtFork(fork, DOMAIN_AGGREGATE_AND_PROOF);
|
|
17
|
-
const sszType =
|
|
17
|
+
const sszType = config.getForkTypes(slot).AggregateAndProof;
|
|
18
18
|
return computeSigningRoot(sszType, aggregateAndProof.message, aggregatorDomain);
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {ContainerType, VectorCompositeType} from "@chainsafe/ssz";
|
|
2
2
|
import {ChainForkConfig} from "@lodestar/config";
|
|
3
3
|
import {DatabaseController, Repository} from "@lodestar/db";
|
|
4
|
+
import {CURRENT_SYNC_COMMITTEE_DEPTH_GLOAS, NEXT_SYNC_COMMITTEE_DEPTH_GLOAS} from "@lodestar/params";
|
|
4
5
|
import {ssz} from "@lodestar/types";
|
|
5
6
|
import {SyncCommitteeWitness} from "../../chain/lightClient/types.js";
|
|
6
7
|
import {Bucket, getBucketNameByValue} from "../buckets.js";
|
|
7
8
|
|
|
8
|
-
// We add a 1-byte prefix where 0 means pre-
|
|
9
|
+
// We add a 1-byte prefix where 0 means pre-Electra, 1 means post-Electra, and 2 means post-Gloas.
|
|
9
10
|
enum PrefixByte {
|
|
10
11
|
PRE_ELECTRA = 0,
|
|
11
12
|
POST_ELECTRA = 1,
|
|
13
|
+
POST_GLOAS = 2,
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
export const NUM_WITNESS = 4;
|
|
@@ -35,6 +37,35 @@ export class SyncCommitteeWitnessRepository extends Repository<Uint8Array, SyncC
|
|
|
35
37
|
// Overrides for multi-fork
|
|
36
38
|
encodeValue(value: SyncCommitteeWitness): Uint8Array {
|
|
37
39
|
const numWitness = value.witness.length;
|
|
40
|
+
const hasGloasBranches =
|
|
41
|
+
value.currentSyncCommitteeBranch !== undefined || value.nextSyncCommitteeBranch !== undefined;
|
|
42
|
+
|
|
43
|
+
if (hasGloasBranches) {
|
|
44
|
+
if (
|
|
45
|
+
value.currentSyncCommitteeBranch?.length !== CURRENT_SYNC_COMMITTEE_DEPTH_GLOAS ||
|
|
46
|
+
value.nextSyncCommitteeBranch?.length !== NEXT_SYNC_COMMITTEE_DEPTH_GLOAS
|
|
47
|
+
) {
|
|
48
|
+
throw Error(
|
|
49
|
+
`Invalid post-Gloas sync committee branch lengths current=${value.currentSyncCommitteeBranch?.length} next=${value.nextSyncCommitteeBranch?.length}`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const type = new ContainerType({
|
|
54
|
+
currentSyncCommitteeBranch: new VectorCompositeType(ssz.Root, CURRENT_SYNC_COMMITTEE_DEPTH_GLOAS),
|
|
55
|
+
nextSyncCommitteeBranch: new VectorCompositeType(ssz.Root, NEXT_SYNC_COMMITTEE_DEPTH_GLOAS),
|
|
56
|
+
currentSyncCommitteeRoot: ssz.Root,
|
|
57
|
+
nextSyncCommitteeRoot: ssz.Root,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const valueBytes = type.serialize({
|
|
61
|
+
currentSyncCommitteeBranch: value.currentSyncCommitteeBranch,
|
|
62
|
+
nextSyncCommitteeBranch: value.nextSyncCommitteeBranch,
|
|
63
|
+
currentSyncCommitteeRoot: value.currentSyncCommitteeRoot,
|
|
64
|
+
nextSyncCommitteeRoot: value.nextSyncCommitteeRoot,
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return prefixData(PrefixByte.POST_GLOAS, valueBytes);
|
|
68
|
+
}
|
|
38
69
|
|
|
39
70
|
if (numWitness !== NUM_WITNESS && numWitness !== NUM_WITNESS_ELECTRA) {
|
|
40
71
|
throw Error(`Number of witness can only be 4 pre-electra or 5 post-electra numWitness=${numWitness}`);
|
|
@@ -51,19 +82,25 @@ export class SyncCommitteeWitnessRepository extends Repository<Uint8Array, SyncC
|
|
|
51
82
|
// We need to differentiate between post-electra and pre-electra witness
|
|
52
83
|
// such that we can deserialize correctly
|
|
53
84
|
const isPostElectra = numWitness === NUM_WITNESS_ELECTRA;
|
|
54
|
-
|
|
55
|
-
prefixByte[0] = isPostElectra ? PrefixByte.POST_ELECTRA : PrefixByte.PRE_ELECTRA;
|
|
56
|
-
|
|
57
|
-
const prefixedData = new Uint8Array(1 + valueBytes.length);
|
|
58
|
-
prefixedData.set(prefixByte, 0);
|
|
59
|
-
prefixedData.set(valueBytes, 1);
|
|
60
|
-
|
|
61
|
-
return prefixedData;
|
|
85
|
+
return prefixData(isPostElectra ? PrefixByte.POST_ELECTRA : PrefixByte.PRE_ELECTRA, valueBytes);
|
|
62
86
|
}
|
|
63
87
|
|
|
64
88
|
decodeValue(data: Uint8Array): SyncCommitteeWitness {
|
|
65
89
|
// First byte is written
|
|
66
90
|
const prefix = data.subarray(0, 1);
|
|
91
|
+
const isPostGloas = prefix[0] === PrefixByte.POST_GLOAS;
|
|
92
|
+
|
|
93
|
+
if (isPostGloas) {
|
|
94
|
+
const type = new ContainerType({
|
|
95
|
+
currentSyncCommitteeBranch: new VectorCompositeType(ssz.Root, CURRENT_SYNC_COMMITTEE_DEPTH_GLOAS),
|
|
96
|
+
nextSyncCommitteeBranch: new VectorCompositeType(ssz.Root, NEXT_SYNC_COMMITTEE_DEPTH_GLOAS),
|
|
97
|
+
currentSyncCommitteeRoot: ssz.Root,
|
|
98
|
+
nextSyncCommitteeRoot: ssz.Root,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return {witness: [], ...type.deserialize(data.subarray(1))};
|
|
102
|
+
}
|
|
103
|
+
|
|
67
104
|
const isPostElectra = prefix[0] === PrefixByte.POST_ELECTRA;
|
|
68
105
|
|
|
69
106
|
const type = new ContainerType({
|
|
@@ -75,3 +112,14 @@ export class SyncCommitteeWitnessRepository extends Repository<Uint8Array, SyncC
|
|
|
75
112
|
return type.deserialize(data.subarray(1));
|
|
76
113
|
}
|
|
77
114
|
}
|
|
115
|
+
|
|
116
|
+
function prefixData(prefix: PrefixByte, valueBytes: Uint8Array): Uint8Array {
|
|
117
|
+
const prefixByte = new Uint8Array(1);
|
|
118
|
+
prefixByte[0] = prefix;
|
|
119
|
+
|
|
120
|
+
const prefixedData = new Uint8Array(1 + valueBytes.length);
|
|
121
|
+
prefixedData.set(prefixByte, 0);
|
|
122
|
+
prefixedData.set(valueBytes, 1);
|
|
123
|
+
|
|
124
|
+
return prefixedData;
|
|
125
|
+
}
|
|
@@ -70,6 +70,33 @@ export class NoBidReceived extends Error {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* Beacon clients select randomized values from the following ranges when initializing
|
|
75
|
+
* the circuit breaker (so at boot time and once for each unique boot).
|
|
76
|
+
*
|
|
77
|
+
* ALLOWED_FAULTS: between 1 and SLOTS_PER_EPOCH // 4
|
|
78
|
+
* FAULT_INSPECTION_WINDOW: between SLOTS_PER_EPOCH and 2 * SLOTS_PER_EPOCH
|
|
79
|
+
*
|
|
80
|
+
* The values are randomized per node so builders cannot predict when a given proposer will
|
|
81
|
+
* fall back to local blocks. With fixed thresholds a builder could withhold payloads right up
|
|
82
|
+
* to the limit without ever tripping the breaker.
|
|
83
|
+
*/
|
|
84
|
+
export function getFaultInspectionParams(opts: {faultInspectionWindow?: number; allowedFaults?: number}): {
|
|
85
|
+
faultInspectionWindow: number;
|
|
86
|
+
allowedFaults: number;
|
|
87
|
+
} {
|
|
88
|
+
const faultInspectionWindow = Math.max(
|
|
89
|
+
opts.faultInspectionWindow ?? SLOTS_PER_EPOCH + Math.floor(Math.random() * SLOTS_PER_EPOCH),
|
|
90
|
+
SLOTS_PER_EPOCH
|
|
91
|
+
);
|
|
92
|
+
// allowedFaults should be < faultInspectionWindow, limiting them to faultInspectionWindow/4
|
|
93
|
+
const allowedFaults = Math.min(
|
|
94
|
+
opts.allowedFaults ?? Math.floor(faultInspectionWindow / 4),
|
|
95
|
+
Math.floor(faultInspectionWindow / 4)
|
|
96
|
+
);
|
|
97
|
+
return {faultInspectionWindow, allowedFaults};
|
|
98
|
+
}
|
|
99
|
+
|
|
73
100
|
/**
|
|
74
101
|
* Additional duration to account for potential event loop lag which causes
|
|
75
102
|
* builder blocks to be rejected even though the response was sent in time.
|
|
@@ -122,23 +149,9 @@ export class ExecutionBuilderHttp implements IExecutionBuilder {
|
|
|
122
149
|
this.registrations = new ValidatorRegistrationCache();
|
|
123
150
|
this.issueLocalFcUWithFeeRecipient = opts.issueLocalFcUWithFeeRecipient;
|
|
124
151
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
*
|
|
129
|
-
* ALLOWED_FAULTS: between 1 and SLOTS_PER_EPOCH // 4
|
|
130
|
-
* FAULT_INSPECTION_WINDOW: between SLOTS_PER_EPOCH and 2 * SLOTS_PER_EPOCH
|
|
131
|
-
*
|
|
132
|
-
*/
|
|
133
|
-
this.faultInspectionWindow = Math.max(
|
|
134
|
-
opts.faultInspectionWindow ?? SLOTS_PER_EPOCH + Math.floor(Math.random() * SLOTS_PER_EPOCH),
|
|
135
|
-
SLOTS_PER_EPOCH
|
|
136
|
-
);
|
|
137
|
-
// allowedFaults should be < faultInspectionWindow, limiting them to faultInspectionWindow/4
|
|
138
|
-
this.allowedFaults = Math.min(
|
|
139
|
-
opts.allowedFaults ?? Math.floor(this.faultInspectionWindow / 4),
|
|
140
|
-
Math.floor(this.faultInspectionWindow / 4)
|
|
141
|
-
);
|
|
152
|
+
const {faultInspectionWindow, allowedFaults} = getFaultInspectionParams(opts);
|
|
153
|
+
this.faultInspectionWindow = faultInspectionWindow;
|
|
154
|
+
this.allowedFaults = allowedFaults;
|
|
142
155
|
}
|
|
143
156
|
|
|
144
157
|
updateStatus(status: BuilderStatus): void {
|
|
@@ -138,6 +138,25 @@ export function createBeaconMetrics(register: RegistryMetricCreator) {
|
|
|
138
138
|
help: "Count of cached produced results",
|
|
139
139
|
}),
|
|
140
140
|
|
|
141
|
+
builderCircuitBreaker: {
|
|
142
|
+
active: register.gauge({
|
|
143
|
+
name: "beacon_builder_circuit_breaker_active",
|
|
144
|
+
help: "Whether the builder circuit breaker is active (1) causing builder bids to be ignored",
|
|
145
|
+
}),
|
|
146
|
+
faults: register.gauge({
|
|
147
|
+
name: "beacon_builder_circuit_breaker_faults",
|
|
148
|
+
help: "Count of blocks with unrevealed payloads in the fault inspection window",
|
|
149
|
+
}),
|
|
150
|
+
blocksPresent: register.gauge({
|
|
151
|
+
name: "beacon_builder_circuit_breaker_blocks_present",
|
|
152
|
+
help: "Count of blocks present in the fault inspection window",
|
|
153
|
+
}),
|
|
154
|
+
payloadsRevealed: register.gauge({
|
|
155
|
+
name: "beacon_builder_circuit_breaker_payloads_revealed",
|
|
156
|
+
help: "Count of blocks with revealed payloads in the fault inspection window",
|
|
157
|
+
}),
|
|
158
|
+
},
|
|
159
|
+
|
|
141
160
|
blockPayload: {
|
|
142
161
|
payloadAdvancePrepTime: register.histogram({
|
|
143
162
|
name: "beacon_block_payload_prepare_time",
|