@lodestar/beacon-node 1.45.0-dev.f535421f29 → 1.45.0-dev.f6c521a123
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.d.ts.map +1 -1
- package/lib/api/impl/beacon/blocks/index.js +3 -2
- package/lib/api/impl/beacon/blocks/index.js.map +1 -1
- 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 +14 -3
- 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 +4 -22
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +13 -5
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.js +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.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 +27 -5
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +48 -6
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +25 -4
- 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 +3 -2
- package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.js +4 -1
- 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/validation/aggregateAndProof.js +10 -6
- package/lib/chain/validation/aggregateAndProof.js.map +1 -1
- package/lib/chain/validation/attestation.d.ts.map +1 -1
- package/lib/chain/validation/attestation.js +10 -6
- package/lib/chain/validation/attestation.js.map +1 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +53 -4
- package/lib/chain/validation/block.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +13 -12
- 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 +29 -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 +18 -9
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +4 -2
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
- package/lib/sync/sync.d.ts.map +1 -1
- package/lib/sync/sync.js +7 -0
- package/lib/sync/sync.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +7 -2
- package/lib/sync/unknownBlock.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 +23 -21
- package/src/api/impl/beacon/blocks/index.ts +3 -2
- 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 +17 -3
- package/src/chain/blocks/importBlock.ts +2 -24
- package/src/chain/blocks/utils/chainSegment.ts +16 -5
- package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +1 -1
- package/src/chain/blocks/verifyBlocksSanityChecks.ts +1 -1
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +2 -2
- package/src/chain/builderCircuitBreaker.ts +84 -0
- package/src/chain/chain.ts +38 -5
- package/src/chain/errors/blockError.ts +44 -7
- 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 +6 -2
- 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/validation/aggregateAndProof.ts +12 -6
- package/src/chain/validation/attestation.ts +12 -6
- package/src/chain/validation/block.ts +69 -4
- package/src/chain/validation/executionPayloadBid.ts +16 -11
- package/src/chain/validation/executionPayloadEnvelope.ts +37 -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 +58 -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 +18 -8
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +4 -2
- package/src/sync/sync.ts +10 -0
- package/src/sync/unknownBlock.ts +8 -2
- 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
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";
|
|
@@ -90,13 +90,19 @@ async function validateAggregateAndProof(
|
|
|
90
90
|
});
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
// [REJECT] If `aggregate.data.index == 1` (payload present for a past
|
|
94
|
-
//
|
|
93
|
+
// [REJECT] If `aggregate.data.index == 1` (payload present for a past block)
|
|
94
|
+
// the corresponding execution payload for `block` passes validation.
|
|
95
95
|
// [IGNORE] When `aggregate.data.index == 1` (payload present for a past block),
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
// payload
|
|
99
|
-
|
|
96
|
+
// the corresponding execution payload for `block` has been fully imported, including its
|
|
97
|
+
// data -- i.e. `is_payload_verified(store, aggregate.data.beacon_block_root)` returns `True`
|
|
98
|
+
// (a client MAY queue attestations for processing until the payload is imported and SHOULD
|
|
99
|
+
// request the payload envelope via `ExecutionPayloadEnvelopesByRoot` using
|
|
100
|
+
// `aggregate.data.beacon_block_root`).
|
|
101
|
+
if (
|
|
102
|
+
block !== null &&
|
|
103
|
+
attData.index === 1 &&
|
|
104
|
+
!chain.forkChoice.hasPayloadHexUnsafe(toRootHex(attData.beaconBlockRoot))
|
|
105
|
+
) {
|
|
100
106
|
throw new AttestationError(GossipAction.IGNORE, {
|
|
101
107
|
code: AttestationErrorCode.EXECUTION_PAYLOAD_NOT_SEEN,
|
|
102
108
|
beaconBlockRoot: toRootHex(attData.beaconBlockRoot),
|
|
@@ -316,13 +316,19 @@ async function validateAttestationNoSignatureCheck(
|
|
|
316
316
|
});
|
|
317
317
|
}
|
|
318
318
|
|
|
319
|
-
// [REJECT] If `attestation.data.index == 1` (payload present for a past
|
|
320
|
-
//
|
|
319
|
+
// [REJECT] If `attestation.data.index == 1` (payload present for a past block),
|
|
320
|
+
// the execution payload for `block` passes validation.
|
|
321
321
|
// [IGNORE] When `attestation.data.index == 1` (payload present for a past block),
|
|
322
|
-
//
|
|
323
|
-
//
|
|
324
|
-
// payload
|
|
325
|
-
|
|
322
|
+
// the execution payload for `block` has been fully imported, including its data -- i.e.
|
|
323
|
+
// `is_payload_verified(store, attestation.data.beacon_block_root)` returns `True`
|
|
324
|
+
// (a client MAY queue attestations for processing until the payload is imported and
|
|
325
|
+
// SHOULD request the payload envelope via `ExecutionPayloadEnvelopesByRoot` using
|
|
326
|
+
// `attestation.data.beacon_block_root`).
|
|
327
|
+
if (
|
|
328
|
+
block !== null &&
|
|
329
|
+
attData.index === 1 &&
|
|
330
|
+
!chain.forkChoice.hasPayloadHexUnsafe(toRootHex(attData.beaconBlockRoot))
|
|
331
|
+
) {
|
|
326
332
|
throw new AttestationError(GossipAction.IGNORE, {
|
|
327
333
|
code: AttestationErrorCode.EXECUTION_PAYLOAD_NOT_SEEN,
|
|
328
334
|
beaconBlockRoot: toRootHex(attData.beaconBlockRoot),
|
|
@@ -1,6 +1,21 @@
|
|
|
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_PAYLOAD_ATTESTATIONS,
|
|
12
|
+
MAX_PROPOSER_SLASHINGS,
|
|
13
|
+
MAX_VOLUNTARY_EXITS,
|
|
14
|
+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
|
|
15
|
+
isForkPostBellatrix,
|
|
16
|
+
isForkPostDeneb,
|
|
17
|
+
isForkPostGloas,
|
|
18
|
+
} from "@lodestar/params";
|
|
4
19
|
import {
|
|
5
20
|
computeEpochAtSlot,
|
|
6
21
|
computeStartSlotAtEpoch,
|
|
@@ -88,8 +103,8 @@ export async function validateGossipBlock(
|
|
|
88
103
|
// 2. The parent is unknown to us, we probably want to download it since it might actually
|
|
89
104
|
// descend from the finalized root.
|
|
90
105
|
// (Non-Lighthouse): Since we prune all blocks non-descendant from finalized checking the `db.block` database won't be useful to guard
|
|
91
|
-
// against known bad fork blocks, so we throw
|
|
92
|
-
throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.
|
|
106
|
+
// against known bad fork blocks, so we throw PARENT_BLOCK_UNKNOWN for cases (1) and (2)
|
|
107
|
+
throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.PARENT_BLOCK_UNKNOWN, parentRoot});
|
|
93
108
|
}
|
|
94
109
|
|
|
95
110
|
// [IGNORE] The block's parent (defined by `block.parent_root`) passes all validation
|
|
@@ -164,6 +179,56 @@ export async function validateGossipBlock(
|
|
|
164
179
|
});
|
|
165
180
|
}
|
|
166
181
|
|
|
182
|
+
// [REJECT] The counts of `block.body.parent_execution_requests` are within
|
|
183
|
+
// their respective limits -- i.e. validate that
|
|
184
|
+
// `len(block.body.parent_execution_requests.withdrawals) <= MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD`,
|
|
185
|
+
// `len(block.body.parent_execution_requests.consolidations) <= MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD`,
|
|
186
|
+
// `len(block.body.parent_execution_requests.builder_deposits) <= MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD`,
|
|
187
|
+
// and
|
|
188
|
+
// `len(block.body.parent_execution_requests.builder_exits) <= MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD`.
|
|
189
|
+
// [REJECT] The counts of the block body operations are within their respective
|
|
190
|
+
// limits -- i.e. validate that
|
|
191
|
+
// `len(block.body.proposer_slashings) <= MAX_PROPOSER_SLASHINGS`,
|
|
192
|
+
// `len(block.body.attester_slashings) <= MAX_ATTESTER_SLASHINGS_ELECTRA`,
|
|
193
|
+
// `len(block.body.attestations) <= MAX_ATTESTATIONS_ELECTRA`,
|
|
194
|
+
// `len(block.body.deposits) == 0`,
|
|
195
|
+
// `len(block.body.voluntary_exits) <= MAX_VOLUNTARY_EXITS`,
|
|
196
|
+
// `len(block.body.bls_to_execution_changes) <= MAX_BLS_TO_EXECUTION_CHANGES`,
|
|
197
|
+
// and `len(block.body.payload_attestations) <= MAX_PAYLOAD_ATTESTATIONS`.
|
|
198
|
+
const body = (block as gloas.BeaconBlock).body;
|
|
199
|
+
const requests = body.parentExecutionRequests;
|
|
200
|
+
const countLimits: [string, number, number][] = [
|
|
201
|
+
["parentExecutionRequests.withdrawals", requests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD],
|
|
202
|
+
[
|
|
203
|
+
"parentExecutionRequests.consolidations",
|
|
204
|
+
requests.consolidations.length,
|
|
205
|
+
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
|
|
206
|
+
],
|
|
207
|
+
[
|
|
208
|
+
"parentExecutionRequests.builderDeposits",
|
|
209
|
+
requests.builderDeposits.length,
|
|
210
|
+
MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
|
|
211
|
+
],
|
|
212
|
+
["parentExecutionRequests.builderExits", requests.builderExits.length, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD],
|
|
213
|
+
["proposerSlashings", body.proposerSlashings.length, MAX_PROPOSER_SLASHINGS],
|
|
214
|
+
["attesterSlashings", body.attesterSlashings.length, MAX_ATTESTER_SLASHINGS_ELECTRA],
|
|
215
|
+
["attestations", body.attestations.length, MAX_ATTESTATIONS_ELECTRA],
|
|
216
|
+
["deposits", body.deposits.length, 0],
|
|
217
|
+
["voluntaryExits", body.voluntaryExits.length, MAX_VOLUNTARY_EXITS],
|
|
218
|
+
["blsToExecutionChanges", body.blsToExecutionChanges.length, MAX_BLS_TO_EXECUTION_CHANGES],
|
|
219
|
+
["payloadAttestations", body.payloadAttestations.length, MAX_PAYLOAD_ATTESTATIONS],
|
|
220
|
+
];
|
|
221
|
+
for (const [name, count, limit] of countLimits) {
|
|
222
|
+
if (count > limit) {
|
|
223
|
+
throw new BlockGossipError(GossipAction.REJECT, {
|
|
224
|
+
code: BlockErrorCode.TOO_MANY_BLOCK_OPERATIONS,
|
|
225
|
+
name,
|
|
226
|
+
count,
|
|
227
|
+
limit,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
167
232
|
// TODO GLOAS: [REJECT] The block's execution payload parent (defined by bid.parent_block_hash) passes all validation
|
|
168
233
|
// This requires execution engine integration to verify the parent block hash
|
|
169
234
|
}
|
|
@@ -176,7 +241,7 @@ export async function validateGossipBlock(
|
|
|
176
241
|
const blockState = await chain.regen
|
|
177
242
|
.getPreState(block, {dontTransferCache: true}, RegenCaller.validateGossipBlock)
|
|
178
243
|
.catch(() => {
|
|
179
|
-
throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.
|
|
244
|
+
throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.PARENT_BLOCK_UNKNOWN, parentRoot});
|
|
180
245
|
});
|
|
181
246
|
|
|
182
247
|
// in forky condition, make sure to populate ShufflingCache with regened state
|
|
@@ -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,
|
|
@@ -160,9 +165,9 @@ async function validateExecutionPayloadBid(
|
|
|
160
165
|
});
|
|
161
166
|
}
|
|
162
167
|
|
|
163
|
-
// [
|
|
168
|
+
// [IGNORE] `bid.fee_recipient == proposer_preferences.fee_recipient`.
|
|
164
169
|
if (!byteArrayEquals(bid.feeRecipient, proposerPreferences.message.feeRecipient)) {
|
|
165
|
-
throw new ExecutionPayloadBidError(GossipAction.
|
|
170
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
166
171
|
code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH,
|
|
167
172
|
builderIndex: bid.builderIndex,
|
|
168
173
|
bidFeeRecipient: toHex(bid.feeRecipient),
|
|
@@ -1,4 +1,11 @@
|
|
|
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_WITHDRAWALS_PER_PAYLOAD,
|
|
7
|
+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
|
|
8
|
+
} from "@lodestar/params";
|
|
2
9
|
import {
|
|
3
10
|
computeStartSlotAtEpoch,
|
|
4
11
|
getExecutionPayloadEnvelopeSignatureSet,
|
|
@@ -115,6 +122,36 @@ async function validateExecutionPayloadEnvelope(
|
|
|
115
122
|
});
|
|
116
123
|
}
|
|
117
124
|
|
|
125
|
+
// [REJECT] The counts of `execution_requests` are within their respective limits.
|
|
126
|
+
// New in Gloas:EIP7688 — progressive lists are unbounded at the type level, so bounds
|
|
127
|
+
// are enforced here in gossip validation.
|
|
128
|
+
const {executionRequests} = envelope;
|
|
129
|
+
const requestCountLimits: [string, number, number][] = [
|
|
130
|
+
["withdrawals", executionRequests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD],
|
|
131
|
+
["consolidations", executionRequests.consolidations.length, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD],
|
|
132
|
+
["builderDeposits", executionRequests.builderDeposits.length, MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD],
|
|
133
|
+
["builderExits", executionRequests.builderExits.length, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD],
|
|
134
|
+
];
|
|
135
|
+
for (const [name, count, limit] of requestCountLimits) {
|
|
136
|
+
if (count > limit) {
|
|
137
|
+
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
138
|
+
code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_COUNT_EXCEEDED,
|
|
139
|
+
name,
|
|
140
|
+
count,
|
|
141
|
+
limit,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// [REJECT] The number of withdrawals is within the limit.
|
|
147
|
+
if (payload.withdrawals.length > MAX_WITHDRAWALS_PER_PAYLOAD) {
|
|
148
|
+
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
149
|
+
code: ExecutionPayloadEnvelopeErrorCode.WITHDRAWALS_COUNT_EXCEEDED,
|
|
150
|
+
count: payload.withdrawals.length,
|
|
151
|
+
limit: MAX_WITHDRAWALS_PER_PAYLOAD,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
118
155
|
// Get the block state to verify the builder's signature.
|
|
119
156
|
const blockState = await chain.regen
|
|
120
157
|
.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",
|