@lodestar/beacon-node 1.45.0-dev.77f7452c30 → 1.45.0-dev.7acc183c2b
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/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 +2 -2
- package/lib/api/impl/beacon/state/index.js.map +1 -1
- package/lib/api/impl/beacon/state/utils.d.ts +2 -1
- package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
- package/lib/api/impl/beacon/state/utils.js +9 -1
- 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 +21 -56
- 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/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/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 +2 -0
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +3 -0
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +29 -5
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +19 -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 +2 -0
- 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/options.d.ts +4 -0
- package/lib/chain/options.d.ts.map +1 -1
- 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/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +55 -4
- package/lib/chain/validation/block.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/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/gossip/encoding.d.ts +2 -2
- package/lib/network/gossip/encoding.d.ts.map +1 -1
- package/lib/network/gossip/encoding.js +15 -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 +2 -2
- package/lib/network/gossip/gossipsub.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +74 -231
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/gossip/topic.js +24 -1
- package/lib/network/gossip/topic.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +6 -5
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/sync/unknownBlock.js +1 -1
- package/lib/sync/unknownBlock.js.map +1 -1
- package/package.json +15 -15
- package/src/api/impl/beacon/blocks/index.ts +3 -2
- package/src/api/impl/beacon/index.ts +1 -1
- package/src/api/impl/beacon/state/index.ts +3 -2
- package/src/api/impl/beacon/state/utils.ts +11 -0
- 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 +21 -62
- package/src/api/rest/base.ts +9 -0
- package/src/chain/blocks/utils/chainSegment.ts +16 -5
- 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 +7 -0
- package/src/chain/errors/blockError.ts +23 -6
- package/src/chain/errors/executionPayloadEnvelope.ts +9 -0
- package/src/chain/interface.ts +2 -0
- 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/options.ts +4 -0
- package/src/chain/prepareNextSlot.ts +11 -7
- package/src/chain/validation/block.ts +72 -4
- package/src/chain/validation/executionPayloadEnvelope.ts +39 -0
- 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/gossip/encoding.ts +13 -7
- package/src/network/gossip/gossipsub.ts +7 -2
- package/src/network/gossip/topic.ts +31 -0
- package/src/network/processor/gossipHandlers.ts +6 -5
- package/src/sync/unknownBlock.ts +1 -1
package/src/chain/options.ts
CHANGED
|
@@ -49,6 +49,10 @@ export type IChainOptions = BlockProcessOpts &
|
|
|
49
49
|
archiveDateEpochs?: number;
|
|
50
50
|
nHistoricalStatesFileDataStore?: boolean;
|
|
51
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;
|
|
52
56
|
};
|
|
53
57
|
|
|
54
58
|
export type BlockProcessOpts = {
|
|
@@ -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
|
|
|
@@ -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,
|
|
@@ -88,8 +104,8 @@ export async function validateGossipBlock(
|
|
|
88
104
|
// 2. The parent is unknown to us, we probably want to download it since it might actually
|
|
89
105
|
// descend from the finalized root.
|
|
90
106
|
// (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.
|
|
107
|
+
// against known bad fork blocks, so we throw PARENT_BLOCK_UNKNOWN for cases (1) and (2)
|
|
108
|
+
throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.PARENT_BLOCK_UNKNOWN, parentRoot});
|
|
93
109
|
}
|
|
94
110
|
|
|
95
111
|
// [IGNORE] The block's parent (defined by `block.parent_root`) passes all validation
|
|
@@ -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
|
}
|
|
@@ -176,7 +244,7 @@ export async function validateGossipBlock(
|
|
|
176
244
|
const blockState = await chain.regen
|
|
177
245
|
.getPreState(block, {dontTransferCache: true}, RegenCaller.validateGossipBlock)
|
|
178
246
|
.catch(() => {
|
|
179
|
-
throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.
|
|
247
|
+
throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.PARENT_BLOCK_UNKNOWN, parentRoot});
|
|
180
248
|
});
|
|
181
249
|
|
|
182
250
|
// in forky condition, make sure to populate ShufflingCache with regened state
|
|
@@ -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)
|
|
@@ -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",
|
|
@@ -9,7 +9,7 @@ import {ForkName} from "@lodestar/params";
|
|
|
9
9
|
import {intToBytes} from "@lodestar/utils";
|
|
10
10
|
import {MESSAGE_DOMAIN_VALID_SNAPPY} from "./constants.js";
|
|
11
11
|
import {Eth2GossipsubMetrics} from "./metrics.js";
|
|
12
|
-
import {GossipTopicCache, getGossipSSZType} from "./topic.js";
|
|
12
|
+
import {GossipTopicCache, getGossipSSZMaxSize, getGossipSSZType} from "./topic.js";
|
|
13
13
|
|
|
14
14
|
// Load WASM
|
|
15
15
|
const xxhash = await xxhashFactory();
|
|
@@ -98,7 +98,7 @@ export function msgIdFn(gossipTopicCache: GossipTopicCache, msg: Message): Uint8
|
|
|
98
98
|
export class DataTransformSnappy implements DataTransform {
|
|
99
99
|
constructor(
|
|
100
100
|
private readonly gossipTopicCache: GossipTopicCache,
|
|
101
|
-
private readonly
|
|
101
|
+
private readonly maxPayloadSize: number,
|
|
102
102
|
private readonly metrics: Eth2GossipsubMetrics | null
|
|
103
103
|
) {}
|
|
104
104
|
|
|
@@ -111,17 +111,18 @@ export class DataTransformSnappy implements DataTransform {
|
|
|
111
111
|
inboundTransform(topicStr: string, data: Uint8Array): Uint8Array {
|
|
112
112
|
// check uncompressed data length before we actually decompress
|
|
113
113
|
const uncompressedDataLength = snappyWasm.decompress_len(data);
|
|
114
|
-
if (uncompressedDataLength > this.maxSizePerMessage) {
|
|
115
|
-
throw Error(`ssz_snappy decoded data length ${uncompressedDataLength} > ${this.maxSizePerMessage}`);
|
|
116
|
-
}
|
|
117
114
|
|
|
118
115
|
const topic = this.gossipTopicCache.getTopic(topicStr);
|
|
119
116
|
const sszType = getGossipSSZType(topic);
|
|
117
|
+
const maxSize = getGossipSSZMaxSize(topic, this.maxPayloadSize, sszType);
|
|
120
118
|
this.metrics?.dataTransform.inbound.inc({type: topic.type});
|
|
121
119
|
|
|
122
120
|
if (uncompressedDataLength < sszType.minSize) {
|
|
123
121
|
throw Error(`ssz_snappy decoded data length ${uncompressedDataLength} < ${sszType.minSize}`);
|
|
124
122
|
}
|
|
123
|
+
if (uncompressedDataLength > maxSize) {
|
|
124
|
+
throw Error(`ssz_snappy decoded data length ${uncompressedDataLength} > ${maxSize}`);
|
|
125
|
+
}
|
|
125
126
|
if (uncompressedDataLength > sszType.maxSize) {
|
|
126
127
|
throw Error(`ssz_snappy decoded data length ${uncompressedDataLength} > ${sszType.maxSize}`);
|
|
127
128
|
}
|
|
@@ -139,9 +140,14 @@ export class DataTransformSnappy implements DataTransform {
|
|
|
139
140
|
*/
|
|
140
141
|
outboundTransform(topicStr: string, data: Uint8Array): Uint8Array {
|
|
141
142
|
const topic = this.gossipTopicCache.getTopic(topicStr);
|
|
143
|
+
const sszType = getGossipSSZType(topic);
|
|
144
|
+
const maxSize = getGossipSSZMaxSize(topic, this.maxPayloadSize, sszType);
|
|
142
145
|
this.metrics?.dataTransform.outbound.inc({type: topic.type});
|
|
143
|
-
if (data.length >
|
|
144
|
-
throw Error(`ssz_snappy encoded data length ${data.length} > ${
|
|
146
|
+
if (data.length > maxSize) {
|
|
147
|
+
throw Error(`ssz_snappy encoded data length ${data.length} > ${maxSize}`);
|
|
148
|
+
}
|
|
149
|
+
if (data.length > sszType.maxSize) {
|
|
150
|
+
throw Error(`ssz_snappy encoded data length ${data.length} > ${sszType.maxSize}`);
|
|
145
151
|
}
|
|
146
152
|
|
|
147
153
|
// Using Buffer.alloc() instead of Buffer.allocUnsafe() to mitigate high GC pressure observed in some environments
|
|
@@ -15,7 +15,12 @@ import {type Multiaddr, multiaddr} from "@multiformats/multiaddr";
|
|
|
15
15
|
import {ENR} from "@chainsafe/enr";
|
|
16
16
|
import {routes} from "@lodestar/api";
|
|
17
17
|
import {BeaconConfig, ForkBoundary} from "@lodestar/config";
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
ATTESTATION_SUBNET_COUNT,
|
|
20
|
+
MAX_SIGNED_AGGREGATE_AND_PROOF_SIZE,
|
|
21
|
+
SLOTS_PER_EPOCH,
|
|
22
|
+
SYNC_COMMITTEE_SUBNET_COUNT,
|
|
23
|
+
} from "@lodestar/params";
|
|
19
24
|
import {SubnetID} from "@lodestar/types";
|
|
20
25
|
import {Logger, Map2d, Map2dArr} from "@lodestar/utils";
|
|
21
26
|
import {RegistryMetricCreator} from "../../metrics/index.js";
|
|
@@ -179,7 +184,7 @@ export class Eth2Gossipsub {
|
|
|
179
184
|
// Only send IDONTWANT messages if the message size is larger than this
|
|
180
185
|
// This should be large enough to not send IDONTWANT for "small" messages
|
|
181
186
|
// See https://github.com/ChainSafe/lodestar/pull/7077#issuecomment-2383679472
|
|
182
|
-
idontwantMinDataSize:
|
|
187
|
+
idontwantMinDataSize: MAX_SIGNED_AGGREGATE_AND_PROOF_SIZE,
|
|
183
188
|
})(modules.libp2p.services.components) as GossipSubInternal;
|
|
184
189
|
|
|
185
190
|
if (metrics) {
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
import {type CompositeTypeAny} from "@chainsafe/ssz";
|
|
1
2
|
import {ForkDigestContext} from "@lodestar/config";
|
|
2
3
|
import {
|
|
3
4
|
ATTESTATION_SUBNET_COUNT,
|
|
4
5
|
ForkName,
|
|
5
6
|
ForkSeq,
|
|
7
|
+
MAX_ATTESTER_SLASHING_SIZE,
|
|
8
|
+
MAX_DATA_COLUMN_SIDECAR_SIZE,
|
|
9
|
+
MAX_SIGNED_AGGREGATE_AND_PROOF_SIZE,
|
|
10
|
+
MAX_SIGNED_BEACON_BLOCK_SIZE,
|
|
11
|
+
MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE,
|
|
6
12
|
SYNC_COMMITTEE_SUBNET_COUNT,
|
|
7
13
|
isForkPostAltair,
|
|
8
14
|
isForkPostElectra,
|
|
9
15
|
isForkPostFulu,
|
|
16
|
+
isForkPostGloas,
|
|
10
17
|
} from "@lodestar/params";
|
|
11
18
|
import {Attestation, SingleAttestation, ssz, sszTypesFor} from "@lodestar/types";
|
|
12
19
|
import {GossipAction, GossipActionError, GossipErrorCode} from "../../chain/errors/gossipValidation.js";
|
|
@@ -130,6 +137,30 @@ export function getGossipSSZType(topic: GossipTopic) {
|
|
|
130
137
|
}
|
|
131
138
|
}
|
|
132
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Return the maximum uncompressed SSZ byte length accepted for a gossip object.
|
|
142
|
+
*/
|
|
143
|
+
export function getGossipSSZMaxSize(topic: GossipTopic, maxPayloadSize: number, sszType?: CompositeTypeAny): number {
|
|
144
|
+
const {fork} = topic.boundary;
|
|
145
|
+
// Gloas progressive containers have broad theoretical SSZ max sizes; use the preset p2p bounds instead.
|
|
146
|
+
switch (topic.type) {
|
|
147
|
+
case GossipType.beacon_block:
|
|
148
|
+
return isForkPostGloas(fork) ? MAX_SIGNED_BEACON_BLOCK_SIZE : maxPayloadSize;
|
|
149
|
+
case GossipType.beacon_aggregate_and_proof:
|
|
150
|
+
return isForkPostGloas(fork) ? MAX_SIGNED_AGGREGATE_AND_PROOF_SIZE : (sszType ?? getGossipSSZType(topic)).maxSize;
|
|
151
|
+
case GossipType.attester_slashing:
|
|
152
|
+
return isForkPostGloas(fork) ? MAX_ATTESTER_SLASHING_SIZE : (sszType ?? getGossipSSZType(topic)).maxSize;
|
|
153
|
+
case GossipType.data_column_sidecar:
|
|
154
|
+
return isForkPostGloas(fork) ? MAX_DATA_COLUMN_SIDECAR_SIZE : (sszType ?? getGossipSSZType(topic)).maxSize;
|
|
155
|
+
case GossipType.execution_payload:
|
|
156
|
+
return maxPayloadSize;
|
|
157
|
+
case GossipType.execution_payload_bid:
|
|
158
|
+
return MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE;
|
|
159
|
+
default:
|
|
160
|
+
return (sszType ?? getGossipSSZType(topic)).maxSize;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
133
164
|
/**
|
|
134
165
|
* Deserialize a gossip serialized data into an ssz object.
|
|
135
166
|
*/
|
|
@@ -176,7 +176,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
176
176
|
|
|
177
177
|
// optimistically add gossip block to the seen cache
|
|
178
178
|
// if validation fails, we will NOT forward this gossip block to peers
|
|
179
|
-
// - if
|
|
179
|
+
// - if PARENT_BLOCK_UNKNOWN error, blockInput will then be queued inside BlockInputSync. If the gossip block is really invalid, it will be pruned there
|
|
180
180
|
// - if other validator errors, blockInput will stay in the seen cache and will be pruned on finalization
|
|
181
181
|
const blockInput = chain.seenBlockInputCache.getByBlock({
|
|
182
182
|
block: signedBlock,
|
|
@@ -187,7 +187,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
187
187
|
});
|
|
188
188
|
|
|
189
189
|
// Optimistically seed the payload-envelope cache too, mirroring seenBlockInputCache above.
|
|
190
|
-
// This ensures we have PayloadEnvelopeInput, even through "
|
|
190
|
+
// This ensures we have PayloadEnvelopeInput, even through "PARENT_BLOCK_UNKNOWN" error
|
|
191
191
|
// see https://github.com/ChainSafe/lodestar/issues/9475
|
|
192
192
|
if (isForkPostGloas(fork)) {
|
|
193
193
|
chain.seenPayloadEnvelopeInputCache.add({
|
|
@@ -227,7 +227,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
227
227
|
if (e instanceof BlockGossipError) {
|
|
228
228
|
logger.debug("Gossip block has error", {slot, root: blockShortHex, code: e.type.code});
|
|
229
229
|
if (
|
|
230
|
-
(e.type.code === BlockErrorCode.
|
|
230
|
+
(e.type.code === BlockErrorCode.PARENT_BLOCK_UNKNOWN ||
|
|
231
|
+
e.type.code === BlockErrorCode.PARENT_PAYLOAD_UNKNOWN) &&
|
|
231
232
|
blockInput
|
|
232
233
|
) {
|
|
233
234
|
chain.emitter.emit(ChainEvent.blockUnknownParent, {
|
|
@@ -661,9 +662,9 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
661
662
|
break;
|
|
662
663
|
}
|
|
663
664
|
// ALREADY_KNOWN should not happen with ignoreIfKnown=true above
|
|
664
|
-
//
|
|
665
|
+
// PARENT_BLOCK_UNKNOWN should not happen, we handled this in validateBeaconBlock() function above
|
|
665
666
|
case BlockErrorCode.ALREADY_KNOWN:
|
|
666
|
-
case BlockErrorCode.
|
|
667
|
+
case BlockErrorCode.PARENT_BLOCK_UNKNOWN:
|
|
667
668
|
case BlockErrorCode.PRESTATE_MISSING:
|
|
668
669
|
case BlockErrorCode.EXECUTION_ENGINE_ERROR:
|
|
669
670
|
// Errors might indicate an issue with our node or the connected EL client
|
package/src/sync/unknownBlock.ts
CHANGED
|
@@ -819,7 +819,7 @@ export class BlockInputSync {
|
|
|
819
819
|
// case BlockErrorCode.ALREADY_KNOWN:
|
|
820
820
|
// case BlockErrorCode.GENESIS_BLOCK:
|
|
821
821
|
|
|
822
|
-
case BlockErrorCode.
|
|
822
|
+
case BlockErrorCode.PARENT_BLOCK_UNKNOWN:
|
|
823
823
|
case BlockErrorCode.PRESTATE_MISSING:
|
|
824
824
|
// Should not happen, mark as downloaded to try again latter
|
|
825
825
|
this.logger.debug("Attempted to process block but its parent was still unknown", errorData, res.err);
|