@lodestar/beacon-node 1.44.0-dev.552cdce8d0 → 1.44.0-dev.6c85077978
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 +30 -0
- package/lib/api/impl/beacon/blocks/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 +1 -1
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +85 -38
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +1 -1
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +4 -2
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/chain.d.ts +1 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +2 -1
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +6 -1
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +1 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +14 -4
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/opPools/executionPayloadBidPool.d.ts +4 -4
- package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
- package/lib/chain/opPools/executionPayloadBidPool.js +6 -4
- package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +2 -1
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +7 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +107 -18
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts +7 -3
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +26 -10
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validatorMonitor.d.ts +1 -0
- package/lib/chain/validatorMonitor.d.ts.map +1 -1
- package/lib/chain/validatorMonitor.js +16 -0
- package/lib/chain/validatorMonitor.js.map +1 -1
- package/lib/execution/builder/index.d.ts +1 -2
- package/lib/execution/builder/index.d.ts.map +1 -1
- package/lib/execution/builder/index.js +0 -1
- package/lib/execution/builder/index.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +1 -0
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/types.d.ts +2 -0
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js +2 -0
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +1 -1
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +4 -3
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +1 -1
- package/lib/network/interface.d.ts +1 -0
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/network.d.ts +1 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +5 -0
- package/lib/network/network.js.map +1 -1
- package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
- package/lib/network/processor/gossipHandlers.js +12 -4
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/package.json +14 -14
- package/src/api/impl/beacon/blocks/index.ts +36 -0
- package/src/api/impl/beacon/pool/index.ts +2 -1
- package/src/api/impl/validator/index.ts +99 -39
- package/src/chain/blocks/importBlock.ts +2 -1
- package/src/chain/blocks/importExecutionPayload.ts +7 -1
- package/src/chain/chain.ts +2 -0
- package/src/chain/errors/executionPayloadBid.ts +4 -1
- package/src/chain/forkChoice/index.ts +14 -4
- package/src/chain/opPools/executionPayloadBidPool.ts +10 -9
- package/src/chain/prepareNextSlot.ts +2 -1
- package/src/chain/produceBlock/produceBlockBody.ts +158 -25
- package/src/chain/validation/executionPayloadBid.ts +32 -14
- package/src/chain/validatorMonitor.ts +18 -0
- package/src/execution/builder/index.ts +1 -4
- package/src/execution/engine/interface.ts +1 -0
- package/src/execution/engine/types.ts +4 -0
- package/src/metrics/metrics/lodestar.ts +4 -3
- package/src/network/interface.ts +1 -0
- package/src/network/network.ts +11 -0
- package/src/network/processor/gossipHandlers.ts +16 -4
- package/lib/execution/builder/utils.d.ts +0 -5
- package/lib/execution/builder/utils.d.ts.map +0 -1
- package/lib/execution/builder/utils.js +0 -17
- package/lib/execution/builder/utils.js.map +0 -1
- package/src/execution/builder/utils.ts +0 -19
|
@@ -12,13 +12,13 @@ type BlockRootHex = string;
|
|
|
12
12
|
type BlockHashHex = string;
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
|
-
* Store the best execution payload bid per slot / (parent block root, parent block hash).
|
|
15
|
+
* Store the best signed execution payload bid per slot / (parent block root, parent block hash).
|
|
16
16
|
*/
|
|
17
17
|
export class ExecutionPayloadBidPool {
|
|
18
18
|
private readonly bidByParentHashByParentRootBySlot = new MapDef<
|
|
19
19
|
Slot,
|
|
20
|
-
MapDef<BlockRootHex, Map<BlockHashHex, gloas.
|
|
21
|
-
>(() => new MapDef<BlockRootHex, Map<BlockHashHex, gloas.
|
|
20
|
+
MapDef<BlockRootHex, Map<BlockHashHex, gloas.SignedExecutionPayloadBid>>
|
|
21
|
+
>(() => new MapDef<BlockRootHex, Map<BlockHashHex, gloas.SignedExecutionPayloadBid>>(() => new Map()));
|
|
22
22
|
private lowestPermissibleSlot = 0;
|
|
23
23
|
|
|
24
24
|
get size(): number {
|
|
@@ -31,8 +31,8 @@ export class ExecutionPayloadBidPool {
|
|
|
31
31
|
return count;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
add(bid: gloas.
|
|
35
|
-
const {slot, parentBlockRoot, parentBlockHash, value} = bid;
|
|
34
|
+
add(bid: gloas.SignedExecutionPayloadBid): InsertOutcome {
|
|
35
|
+
const {slot, parentBlockRoot, parentBlockHash, value} = bid.message;
|
|
36
36
|
const lowestPermissibleSlot = this.lowestPermissibleSlot;
|
|
37
37
|
|
|
38
38
|
if (slot < lowestPermissibleSlot) {
|
|
@@ -45,7 +45,7 @@ export class ExecutionPayloadBidPool {
|
|
|
45
45
|
const existing = bidByParentHash.get(parentHashHex);
|
|
46
46
|
|
|
47
47
|
if (existing) {
|
|
48
|
-
const existingValue = existing.value;
|
|
48
|
+
const existingValue = existing.message.value;
|
|
49
49
|
const newValue = value;
|
|
50
50
|
if (newValue > existingValue) {
|
|
51
51
|
bidByParentHash.set(parentHashHex, bid);
|
|
@@ -59,14 +59,15 @@ export class ExecutionPayloadBidPool {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/**
|
|
62
|
-
* Return the highest-value bid matching slot, parent block hash, and parent block root.
|
|
62
|
+
* Return the highest-value signed bid matching slot, parent block hash, and parent block root.
|
|
63
63
|
* Used for gossip validation and block production.
|
|
64
64
|
*/
|
|
65
65
|
getBestBid(
|
|
66
66
|
slot: Slot,
|
|
67
|
-
parentBlockHash: BlockHashHex,
|
|
67
|
+
parentBlockHash: BlockHashHex | null,
|
|
68
68
|
parentBlockRoot: BlockRootHex
|
|
69
|
-
): gloas.
|
|
69
|
+
): gloas.SignedExecutionPayloadBid | null {
|
|
70
|
+
if (parentBlockHash === null) return null;
|
|
70
71
|
const bidByParentHash = this.bidByParentHashByParentRootBySlot.get(slot)?.get(parentBlockRoot);
|
|
71
72
|
return bidByParentHash?.get(parentBlockHash) ?? null;
|
|
72
73
|
}
|
|
@@ -169,7 +169,8 @@ export class PrepareNextSlotScheduler {
|
|
|
169
169
|
// Apply parent payload once here as it's reused by EL prep and SSE emit below
|
|
170
170
|
let stateAfterParentPayload: IBeaconStateViewBellatrix = updatedPrepareState;
|
|
171
171
|
if (isStatePostGloas(updatedPrepareState)) {
|
|
172
|
-
|
|
172
|
+
// Spec: should_build_on_full(store, head) — see produceBlockBody.ts for context.
|
|
173
|
+
if (this.chain.forkChoice.shouldBuildOnFull(updatedHead)) {
|
|
173
174
|
parentBlockHash = updatedPrepareState.latestExecutionPayloadBid.blockHash;
|
|
174
175
|
// Skip applying parent payload unless we're proposing the next slot or have to emit payload_attributes events
|
|
175
176
|
if (feeRecipient !== undefined || this.chain.opts.emitPayloadAttributes === true) {
|
|
@@ -18,7 +18,9 @@ import {
|
|
|
18
18
|
G2_POINT_AT_INFINITY,
|
|
19
19
|
IBeaconStateView,
|
|
20
20
|
type IBeaconStateViewBellatrix,
|
|
21
|
+
computeEpochAtSlot,
|
|
21
22
|
computeTimeAtSlot,
|
|
23
|
+
getExpectedGasLimit,
|
|
22
24
|
isStatePostBellatrix,
|
|
23
25
|
isStatePostCapella,
|
|
24
26
|
isStatePostGloas,
|
|
@@ -48,20 +50,16 @@ import {
|
|
|
48
50
|
gloas,
|
|
49
51
|
ssz,
|
|
50
52
|
} from "@lodestar/types";
|
|
51
|
-
import {Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
|
|
53
|
+
import {GWEI_TO_WEI, Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
|
|
52
54
|
import {ZERO_HASH_HEX} from "../../constants/index.js";
|
|
53
55
|
import {numToQuantity} from "../../execution/engine/utils.js";
|
|
54
|
-
import {
|
|
55
|
-
|
|
56
|
-
IExecutionEngine,
|
|
57
|
-
PayloadAttributes,
|
|
58
|
-
PayloadId,
|
|
59
|
-
getExpectedGasLimit,
|
|
60
|
-
} from "../../execution/index.js";
|
|
56
|
+
import {IExecutionBuilder, IExecutionEngine, PayloadAttributes, PayloadId} from "../../execution/index.js";
|
|
57
|
+
import {getShufflingDependentRoot} from "../../util/dependentRoot.js";
|
|
61
58
|
import {fromGraffitiBytes} from "../../util/graffiti.js";
|
|
62
59
|
import {kzg} from "../../util/kzg.js";
|
|
63
60
|
import type {BeaconChain} from "../chain.js";
|
|
64
61
|
import {CommonBlockBody} from "../interface.js";
|
|
62
|
+
import {ProposerPreferencesPool} from "../opPools/index.js";
|
|
65
63
|
import {validateBlobsAndKzgCommitments, validateCellsAndKzgCommitments} from "./validateBlobsAndKzgCommitments.js";
|
|
66
64
|
|
|
67
65
|
// Time to provide the EL to generate a payload from new payload id
|
|
@@ -93,6 +91,8 @@ export type BlockAttributes = {
|
|
|
93
91
|
slot: Slot;
|
|
94
92
|
parentBlock: ProtoBlock;
|
|
95
93
|
feeRecipient?: string;
|
|
94
|
+
/** When provided, build block with this builder bid instead of a self-build bid */
|
|
95
|
+
builderBid?: gloas.SignedExecutionPayloadBid;
|
|
96
96
|
};
|
|
97
97
|
|
|
98
98
|
export enum BlockType {
|
|
@@ -152,6 +152,28 @@ export type ProduceResult =
|
|
|
152
152
|
| ProduceFullPhase0
|
|
153
153
|
| ProduceBlinded;
|
|
154
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Drop voluntary exits that `parent_execution_requests` have invalidated (e.g. a withdrawal
|
|
157
|
+
* request initiating an exit on the same validator). Op pool selected against the unapplied
|
|
158
|
+
* state, so re-validate against the post-apply state to avoid producing an invalid block.
|
|
159
|
+
*
|
|
160
|
+
* `getStateAfterParentPayload` is a thunk so the post-apply state is only materialized when
|
|
161
|
+
* actually needed (i.e. when extending the parent payload and there are exits to filter).
|
|
162
|
+
*/
|
|
163
|
+
function maybeFilterInvalidatedVoluntaryExits(
|
|
164
|
+
commonBlockBody: CommonBlockBody,
|
|
165
|
+
isExtendingPayload: boolean,
|
|
166
|
+
getStateAfterParentPayload: () => IBeaconStateViewBellatrix
|
|
167
|
+
): CommonBlockBody["voluntaryExits"] {
|
|
168
|
+
if (!isExtendingPayload || commonBlockBody.voluntaryExits.length === 0) {
|
|
169
|
+
return commonBlockBody.voluntaryExits;
|
|
170
|
+
}
|
|
171
|
+
const state = getStateAfterParentPayload();
|
|
172
|
+
return commonBlockBody.voluntaryExits.filter((signedVoluntaryExit) =>
|
|
173
|
+
state.isValidVoluntaryExit(signedVoluntaryExit, false)
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
155
177
|
export async function produceBlockBody<T extends BlockType>(
|
|
156
178
|
this: BeaconChain,
|
|
157
179
|
blockType: T,
|
|
@@ -174,6 +196,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
174
196
|
proposerIndex,
|
|
175
197
|
proposerPubKey,
|
|
176
198
|
commonBlockBodyPromise,
|
|
199
|
+
builderBid,
|
|
177
200
|
} = blockAttr;
|
|
178
201
|
let executionPayloadValue: Wei;
|
|
179
202
|
let blockBody: AssembledBodyType<T>;
|
|
@@ -194,7 +217,43 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
194
217
|
};
|
|
195
218
|
this.logger.verbose("Producing beacon block body", logMeta);
|
|
196
219
|
|
|
197
|
-
if (
|
|
220
|
+
if (builderBid !== undefined) {
|
|
221
|
+
if (!isStatePostGloas(currentState)) {
|
|
222
|
+
throw new Error("Expected Gloas state for builder bid block production");
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const isExtendingPayload = byteArrayEquals(
|
|
226
|
+
builderBid.message.parentBlockHash,
|
|
227
|
+
currentState.latestExecutionPayloadBid.blockHash
|
|
228
|
+
);
|
|
229
|
+
const parentExecutionRequests = isExtendingPayload
|
|
230
|
+
? await this.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot)
|
|
231
|
+
: ssz.electra.ExecutionRequests.defaultValue();
|
|
232
|
+
executionPayloadValue = BigInt(builderBid.message.value) * GWEI_TO_WEI;
|
|
233
|
+
|
|
234
|
+
const commonBlockBody = await commonBlockBodyPromise;
|
|
235
|
+
const gloasBody = Object.assign({}, commonBlockBody) as gloas.BeaconBlockBody;
|
|
236
|
+
gloasBody.signedExecutionPayloadBid = builderBid;
|
|
237
|
+
gloasBody.payloadAttestations = this.payloadAttestationPool.getPayloadAttestationsForBlock(
|
|
238
|
+
parentBlock.blockRoot,
|
|
239
|
+
blockSlot - 1
|
|
240
|
+
);
|
|
241
|
+
gloasBody.parentExecutionRequests = parentExecutionRequests;
|
|
242
|
+
gloasBody.voluntaryExits = maybeFilterInvalidatedVoluntaryExits(commonBlockBody, isExtendingPayload, () =>
|
|
243
|
+
currentState.withParentPayloadApplied(parentExecutionRequests)
|
|
244
|
+
);
|
|
245
|
+
blockBody = gloasBody as AssembledBodyType<T>;
|
|
246
|
+
|
|
247
|
+
this.logger.verbose("Produced block with builder bid", {
|
|
248
|
+
slot: blockSlot,
|
|
249
|
+
builderIndex: builderBid.message.builderIndex,
|
|
250
|
+
bidValue: builderBid.message.value,
|
|
251
|
+
parentBlockHash: toRootHex(builderBid.message.parentBlockHash),
|
|
252
|
+
parentBlockRoot: toRootHex(builderBid.message.parentBlockRoot),
|
|
253
|
+
blockHash: toRootHex(builderBid.message.blockHash),
|
|
254
|
+
isExtendingPayload,
|
|
255
|
+
});
|
|
256
|
+
} else if (isForkPostGloas(fork)) {
|
|
198
257
|
if (!isStatePostGloas(currentState)) {
|
|
199
258
|
throw new Error("Expected Gloas state for Gloas block production");
|
|
200
259
|
}
|
|
@@ -204,23 +263,23 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
204
263
|
// this into a completely separate function and have pre/post gloas more separated
|
|
205
264
|
const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice);
|
|
206
265
|
const finalizedBlockHash = this.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
|
|
266
|
+
// TODO GLOAS: post-Gloas, proposer feeRecipient is also carried (signed) in
|
|
267
|
+
// ProposerPreferencesPool. Consider using this unified cache instead
|
|
268
|
+
// see https://github.com/ChainSafe/lodestar/issues/9379
|
|
207
269
|
const feeRecipient = requestedFeeRecipient ?? this.beaconProposerCache.getOrDefault(proposerIndex);
|
|
208
270
|
|
|
209
271
|
const endExecutionPayload = this.metrics?.executionBlockProductionTimeSteps.startTimer();
|
|
210
272
|
|
|
211
|
-
this.logger.verbose("Preparing execution payload from engine", {
|
|
212
|
-
slot: blockSlot,
|
|
213
|
-
parentBlockRoot: toRootHex(parentBlockRoot),
|
|
214
|
-
feeRecipient,
|
|
215
|
-
});
|
|
216
|
-
|
|
217
273
|
// Get execution payload from EL
|
|
218
274
|
let parentBlockHash: Bytes32;
|
|
219
275
|
let parentExecutionRequests: electra.ExecutionRequests;
|
|
220
276
|
// Apply parent payload once here as it's reused by EL prep and voluntary exit filtering below
|
|
221
277
|
let stateAfterParentPayload: IBeaconStateViewBellatrix = currentState;
|
|
222
|
-
|
|
223
|
-
|
|
278
|
+
// Spec: should_build_on_full(store, head). `parentBlock` is the proposer's head
|
|
279
|
+
// (set by chain.getProposerHead(slot)). Returns false when the PTC majority
|
|
280
|
+
// signalled the blob data is not available, forcing a build on EMPTY (reorg).
|
|
281
|
+
const isBuildingOnFull = this.forkChoice.shouldBuildOnFull(parentBlock);
|
|
282
|
+
if (isBuildingOnFull) {
|
|
224
283
|
parentBlockHash = currentState.latestExecutionPayloadBid.blockHash;
|
|
225
284
|
parentExecutionRequests = await this.getParentExecutionRequests(parentBlock.slot, parentBlock.blockRoot);
|
|
226
285
|
stateAfterParentPayload = currentState.withParentPayloadApplied(parentExecutionRequests);
|
|
@@ -243,6 +302,16 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
243
302
|
const {prepType, payloadId} = prepareRes;
|
|
244
303
|
Object.assign(logMeta, {executionPayloadPrepType: prepType});
|
|
245
304
|
|
|
305
|
+
this.logger.verbose("Prepared execution payload from engine", {
|
|
306
|
+
slot: blockSlot,
|
|
307
|
+
parentBlockRoot: toRootHex(parentBlockRoot),
|
|
308
|
+
parentBlockHash: toRootHex(parentBlockHash),
|
|
309
|
+
feeRecipient,
|
|
310
|
+
prepType,
|
|
311
|
+
payloadId,
|
|
312
|
+
isBuildingOnFull,
|
|
313
|
+
});
|
|
314
|
+
|
|
246
315
|
if (prepType !== PayloadPreparationType.Cached) {
|
|
247
316
|
await sleep(PAYLOAD_GENERATION_TIME_MS);
|
|
248
317
|
}
|
|
@@ -296,14 +365,11 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
296
365
|
blockSlot - 1
|
|
297
366
|
);
|
|
298
367
|
gloasBody.parentExecutionRequests = parentExecutionRequests;
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
stateAfterParentPayload.isValidVoluntaryExit(signedVoluntaryExit, false)
|
|
305
|
-
);
|
|
306
|
-
}
|
|
368
|
+
gloasBody.voluntaryExits = maybeFilterInvalidatedVoluntaryExits(
|
|
369
|
+
commonBlockBody,
|
|
370
|
+
isBuildingOnFull,
|
|
371
|
+
() => stateAfterParentPayload
|
|
372
|
+
);
|
|
307
373
|
blockBody = gloasBody as AssembledBodyType<T>;
|
|
308
374
|
|
|
309
375
|
// Store execution payload data required to construct execution payload envelope later
|
|
@@ -324,6 +390,7 @@ export async function produceBlockBody<T extends BlockType>(
|
|
|
324
390
|
fetchedTime,
|
|
325
391
|
executionBlockHash: toRootHex(executionPayload.blockHash),
|
|
326
392
|
blobs: blobsBundle.commitments.length,
|
|
393
|
+
gasLimit: executionPayload.gasLimit,
|
|
327
394
|
});
|
|
328
395
|
|
|
329
396
|
Object.assign(logMeta, {
|
|
@@ -633,6 +700,8 @@ export async function prepareExecutionPayload(
|
|
|
633
700
|
chain: {
|
|
634
701
|
executionEngine: IExecutionEngine;
|
|
635
702
|
config: ChainForkConfig;
|
|
703
|
+
forkChoice: IForkChoice;
|
|
704
|
+
proposerPreferencesPool: ProposerPreferencesPool;
|
|
636
705
|
},
|
|
637
706
|
logger: Logger,
|
|
638
707
|
fork: ForkPostBellatrix,
|
|
@@ -733,6 +802,7 @@ export function getPayloadAttributesForSSE(
|
|
|
733
802
|
chain: {
|
|
734
803
|
config: ChainForkConfig;
|
|
735
804
|
forkChoice: IForkChoice;
|
|
805
|
+
proposerPreferencesPool: ProposerPreferencesPool;
|
|
736
806
|
},
|
|
737
807
|
{
|
|
738
808
|
prepareState,
|
|
@@ -789,6 +859,8 @@ function preparePayloadAttributes(
|
|
|
789
859
|
fork: ForkPostBellatrix,
|
|
790
860
|
chain: {
|
|
791
861
|
config: ChainForkConfig;
|
|
862
|
+
forkChoice: IForkChoice;
|
|
863
|
+
proposerPreferencesPool: ProposerPreferencesPool;
|
|
792
864
|
},
|
|
793
865
|
{
|
|
794
866
|
prepareState,
|
|
@@ -851,12 +923,73 @@ function preparePayloadAttributes(
|
|
|
851
923
|
}
|
|
852
924
|
|
|
853
925
|
if (ForkSeq[fork] >= ForkSeq.gloas) {
|
|
926
|
+
if (!isStatePostGloas(prepareState)) {
|
|
927
|
+
throw new Error("Expected Gloas state for Gloas payload attributes");
|
|
928
|
+
}
|
|
854
929
|
(payloadAttributes as gloas.SSEPayloadAttributes["payloadAttributes"]).slotNumber = prepareSlot;
|
|
930
|
+
(payloadAttributes as gloas.SSEPayloadAttributes["payloadAttributes"]).targetGasLimit = getProposerTargetGasLimit(
|
|
931
|
+
chain,
|
|
932
|
+
prepareSlot,
|
|
933
|
+
parentBlockRoot,
|
|
934
|
+
parentBlockHash
|
|
935
|
+
);
|
|
855
936
|
}
|
|
856
937
|
|
|
857
938
|
return payloadAttributes;
|
|
858
939
|
}
|
|
859
940
|
|
|
941
|
+
/**
|
|
942
|
+
* Resolve the proposer's preferred (target) gas limit for the Gloas `PayloadAttributesV4`
|
|
943
|
+
* `targetGasLimit` field (consensus-specs#5235, execution-apis#796).
|
|
944
|
+
*
|
|
945
|
+
* Sourced from the `SignedProposerPreferences` the proposer's VC submitted to the pool
|
|
946
|
+
* (same `(slot, dependent_root)` lookup as gossip bid validation). When no matching
|
|
947
|
+
* preferences are pooled, target the parent payload's gas limit so the gas limit stays
|
|
948
|
+
* unchanged (`is_gas_limit_target_compatible` then requires `gas_limit == parent_gas_limit`).
|
|
949
|
+
*
|
|
950
|
+
* The parent payload's gas_limit is read from fork choice — the variant matching
|
|
951
|
+
* `(parentBlockRoot, parentBlockHash)` carries the correct value for both FULL parents
|
|
952
|
+
* (FULL.executionPayloadGasLimit = delivered payload's gas_limit) and EMPTY parents
|
|
953
|
+
* (EMPTY.executionPayloadGasLimit = inherited grandparent's gas_limit).
|
|
954
|
+
*/
|
|
955
|
+
function getProposerTargetGasLimit(
|
|
956
|
+
chain: {forkChoice: IForkChoice; proposerPreferencesPool: ProposerPreferencesPool},
|
|
957
|
+
prepareSlot: Slot,
|
|
958
|
+
parentBlockRoot: Root,
|
|
959
|
+
parentBlockHash: Bytes32
|
|
960
|
+
): number {
|
|
961
|
+
const parentBlockRootHex = toRootHex(parentBlockRoot);
|
|
962
|
+
const parentBlock = chain.forkChoice.getBlockHexDefaultStatus(parentBlockRootHex);
|
|
963
|
+
const dependentRootHex = (() => {
|
|
964
|
+
if (parentBlock === null) {
|
|
965
|
+
return null;
|
|
966
|
+
}
|
|
967
|
+
try {
|
|
968
|
+
return getShufflingDependentRoot(
|
|
969
|
+
chain.forkChoice,
|
|
970
|
+
computeEpochAtSlot(prepareSlot),
|
|
971
|
+
computeEpochAtSlot(parentBlock.slot),
|
|
972
|
+
parentBlock
|
|
973
|
+
);
|
|
974
|
+
} catch {
|
|
975
|
+
return null;
|
|
976
|
+
}
|
|
977
|
+
})();
|
|
978
|
+
|
|
979
|
+
const pref = dependentRootHex !== null ? chain.proposerPreferencesPool.get(prepareSlot, dependentRootHex) : null;
|
|
980
|
+
if (pref !== null) {
|
|
981
|
+
return pref.message.targetGasLimit;
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
const parentPayloadVariant = chain.forkChoice.getBlockHexAndBlockHash(parentBlockRootHex, toRootHex(parentBlockHash));
|
|
985
|
+
if (parentPayloadVariant === null || parentPayloadVariant.executionPayloadBlockHash === null) {
|
|
986
|
+
throw new Error(
|
|
987
|
+
`Cannot resolve parent payload gas_limit for proposer targetGasLimit fallback parentBlockRoot=${parentBlockRootHex} parentBlockHash=${toRootHex(parentBlockHash)}`
|
|
988
|
+
);
|
|
989
|
+
}
|
|
990
|
+
return parentPayloadVariant.executionPayloadGasLimit;
|
|
991
|
+
}
|
|
992
|
+
|
|
860
993
|
export async function produceCommonBlockBody<T extends BlockType>(
|
|
861
994
|
this: BeaconChain,
|
|
862
995
|
blockType: T,
|
|
@@ -4,9 +4,10 @@ import {
|
|
|
4
4
|
createSingleSignatureSetFromComponents,
|
|
5
5
|
getExecutionPayloadBidSigningRoot,
|
|
6
6
|
isActiveBuilder,
|
|
7
|
+
isGasLimitTargetCompatible,
|
|
7
8
|
isStatePostGloas,
|
|
8
9
|
} from "@lodestar/state-transition";
|
|
9
|
-
import {gloas} from "@lodestar/types";
|
|
10
|
+
import {ValidatorIndex, gloas} from "@lodestar/types";
|
|
10
11
|
import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
|
|
11
12
|
import {getShufflingDependentRoot} from "../../util/dependentRoot.js";
|
|
12
13
|
import {ExecutionPayloadBidError, ExecutionPayloadBidErrorCode, GossipAction} from "../errors/index.js";
|
|
@@ -16,21 +17,21 @@ import {RegenCaller} from "../regen/index.js";
|
|
|
16
17
|
export async function validateApiExecutionPayloadBid(
|
|
17
18
|
chain: IBeaconChain,
|
|
18
19
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
19
|
-
): Promise<
|
|
20
|
+
): Promise<{proposerIndex: ValidatorIndex}> {
|
|
20
21
|
return validateExecutionPayloadBid(chain, signedExecutionPayloadBid);
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export async function validateGossipExecutionPayloadBid(
|
|
24
25
|
chain: IBeaconChain,
|
|
25
26
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
26
|
-
): Promise<
|
|
27
|
+
): Promise<{proposerIndex: ValidatorIndex}> {
|
|
27
28
|
return validateExecutionPayloadBid(chain, signedExecutionPayloadBid);
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
async function validateExecutionPayloadBid(
|
|
31
32
|
chain: IBeaconChain,
|
|
32
33
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
33
|
-
): Promise<
|
|
34
|
+
): Promise<{proposerIndex: ValidatorIndex}> {
|
|
34
35
|
const bid = signedExecutionPayloadBid.message;
|
|
35
36
|
const parentBlockRootHex = toRootHex(bid.parentBlockRoot);
|
|
36
37
|
const parentBlockHashHex = toRootHex(bid.parentBlockHash);
|
|
@@ -128,14 +129,33 @@ async function validateExecutionPayloadBid(
|
|
|
128
129
|
});
|
|
129
130
|
}
|
|
130
131
|
|
|
131
|
-
// [
|
|
132
|
+
// [IGNORE] `bid.parent_block_hash` is the block hash of a known execution payload in fork
|
|
133
|
+
// choice. Looks up the variant of `bid.parent_block_root` whose payload hash matches
|
|
134
|
+
// `bid.parent_block_hash` — works for both FULL parents (FULL variant carries the delivered
|
|
135
|
+
// payload's hash) and EMPTY parents (EMPTY/PENDING variants carry the inherited parent
|
|
136
|
+
// payload's hash, since the new block doesn't have its own payload). Variant carries the
|
|
137
|
+
// executed payload's gas_limit, which we use as `parent_gas_limit` below.
|
|
138
|
+
const parentPayloadVariant = chain.forkChoice.getBlockHexAndBlockHash(parentBlockRootHex, parentBlockHashHex);
|
|
139
|
+
if (parentPayloadVariant === null || parentPayloadVariant.executionPayloadBlockHash === null) {
|
|
140
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
141
|
+
code: ExecutionPayloadBidErrorCode.UNKNOWN_PARENT_BLOCK_HASH,
|
|
142
|
+
parentBlockHash: parentBlockHashHex,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// [IGNORE] `is_gas_limit_target_compatible(parent_gas_limit, bid.gas_limit, target_gas_limit)`,
|
|
147
|
+
// where `parent_gas_limit` is the `gas_limit` of the parent execution payload and
|
|
148
|
+
// `target_gas_limit` is `proposer_preferences.target_gas_limit`.
|
|
132
149
|
const bidGasLimit = Number(bid.gasLimit);
|
|
133
|
-
|
|
134
|
-
|
|
150
|
+
const parentGasLimit = parentPayloadVariant.executionPayloadGasLimit;
|
|
151
|
+
const targetGasLimit = proposerPreferences.message.targetGasLimit;
|
|
152
|
+
if (!isGasLimitTargetCompatible(parentGasLimit, bidGasLimit, targetGasLimit)) {
|
|
153
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
135
154
|
code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_GAS_LIMIT_MISMATCH,
|
|
136
155
|
builderIndex: bid.builderIndex,
|
|
137
156
|
bidGasLimit,
|
|
138
|
-
|
|
157
|
+
parentGasLimit,
|
|
158
|
+
targetGasLimit,
|
|
139
159
|
});
|
|
140
160
|
}
|
|
141
161
|
|
|
@@ -166,11 +186,11 @@ async function validateExecutionPayloadBid(
|
|
|
166
186
|
// [IGNORE] this bid is the highest value bid seen for the tuple
|
|
167
187
|
// `(bid.slot, bid.parent_block_hash, bid.parent_block_root)`.
|
|
168
188
|
const bestBid = chain.executionPayloadBidPool.getBestBid(bid.slot, parentBlockHashHex, parentBlockRootHex);
|
|
169
|
-
if (bestBid !== null && bestBid.value >= bid.value) {
|
|
189
|
+
if (bestBid !== null && bestBid.message.value >= bid.value) {
|
|
170
190
|
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
171
191
|
code: ExecutionPayloadBidErrorCode.BID_TOO_LOW,
|
|
172
192
|
bidValue: bid.value,
|
|
173
|
-
currentHighestBid: bestBid.value,
|
|
193
|
+
currentHighestBid: bestBid.message.value,
|
|
174
194
|
});
|
|
175
195
|
}
|
|
176
196
|
// [IGNORE] `bid.value` is less or equal than the builder's excess balance --
|
|
@@ -183,10 +203,6 @@ async function validateExecutionPayloadBid(
|
|
|
183
203
|
});
|
|
184
204
|
}
|
|
185
205
|
|
|
186
|
-
// [IGNORE] `bid.parent_block_hash` is the block hash of a known execution
|
|
187
|
-
// payload in fork choice.
|
|
188
|
-
// TODO GLOAS: implement this
|
|
189
|
-
|
|
190
206
|
// [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
|
|
191
207
|
const signatureSet = createSingleSignatureSetFromComponents(
|
|
192
208
|
PublicKey.fromBytes(builder.pubkey),
|
|
@@ -204,4 +220,6 @@ async function validateExecutionPayloadBid(
|
|
|
204
220
|
|
|
205
221
|
// Valid
|
|
206
222
|
chain.seenExecutionPayloadBids.add(bid.slot, bid.builderIndex);
|
|
223
|
+
|
|
224
|
+
return {proposerIndex: proposerPreferences.message.validatorIndex};
|
|
207
225
|
}
|
|
@@ -66,6 +66,7 @@ export type ValidatorMonitor = {
|
|
|
66
66
|
delaySec: Seconds,
|
|
67
67
|
envelope: gloas.SignedExecutionPayloadEnvelope
|
|
68
68
|
): void;
|
|
69
|
+
registerExecutionPayloadBid(src: OpSource, proposerIndex: ValidatorIndex, bid: gloas.ExecutionPayloadBid): void;
|
|
69
70
|
registerImportedBlock(block: BeaconBlock, data: {proposerBalanceDelta: number}): void;
|
|
70
71
|
onPoolSubmitUnaggregatedAttestation(
|
|
71
72
|
seenTimestampSec: number,
|
|
@@ -459,6 +460,23 @@ export function createValidatorMonitor(
|
|
|
459
460
|
// TODO GLOAS: implement execution payload envelope monitoring
|
|
460
461
|
},
|
|
461
462
|
|
|
463
|
+
registerExecutionPayloadBid(src, proposerIndex, bid) {
|
|
464
|
+
if (!validators.has(proposerIndex)) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
log("Received an execution payload bid for monitored proposer", {
|
|
468
|
+
slot: bid.slot,
|
|
469
|
+
proposerIndex,
|
|
470
|
+
src,
|
|
471
|
+
builderIndex: bid.builderIndex,
|
|
472
|
+
gasLimit: bid.gasLimit,
|
|
473
|
+
value: bid.value.toString(),
|
|
474
|
+
parentBlockRoot: toRootHex(bid.parentBlockRoot),
|
|
475
|
+
parentBlockHash: toRootHex(bid.parentBlockHash),
|
|
476
|
+
blockHash: toRootHex(bid.blockHash),
|
|
477
|
+
});
|
|
478
|
+
},
|
|
479
|
+
|
|
462
480
|
registerImportedBlock(block, {proposerBalanceDelta}) {
|
|
463
481
|
const validator = validators.get(block.proposerIndex);
|
|
464
482
|
if (validator) {
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import {ChainForkConfig} from "@lodestar/config";
|
|
2
2
|
import {Logger} from "@lodestar/logger";
|
|
3
3
|
import {Metrics} from "../../metrics/metrics.js";
|
|
4
|
-
import {IExecutionBuilder} from "./interface.js";
|
|
5
|
-
|
|
6
|
-
export {getExpectedGasLimit} from "./utils.js";
|
|
7
|
-
|
|
8
4
|
import {ExecutionBuilderHttp, ExecutionBuilderHttpOpts, defaultExecutionBuilderHttpOpts} from "./http.js";
|
|
5
|
+
import {IExecutionBuilder} from "./interface.js";
|
|
9
6
|
|
|
10
7
|
export {ExecutionBuilderHttp, defaultExecutionBuilderHttpOpts};
|
|
11
8
|
|
|
@@ -88,6 +88,7 @@ export type PayloadAttributes = {
|
|
|
88
88
|
withdrawals?: capella.Withdrawal[];
|
|
89
89
|
parentBeaconBlockRoot?: Uint8Array;
|
|
90
90
|
slotNumber?: number; // EIP-7843
|
|
91
|
+
targetGasLimit?: number; // GLOAS (PayloadAttributesV4, execution-apis#796)
|
|
91
92
|
};
|
|
92
93
|
|
|
93
94
|
export type VersionedHashes = Uint8Array[];
|
|
@@ -245,6 +245,8 @@ export type PayloadAttributesRpc = {
|
|
|
245
245
|
parentBeaconBlockRoot?: DATA;
|
|
246
246
|
/** QUANTITY, 64 Bits - value for the slot number field of the new payload (EIP-7843) */
|
|
247
247
|
slotNumber?: QUANTITY;
|
|
248
|
+
/** QUANTITY, 64 Bits - target value for the gasLimit field of the new payload (GLOAS, execution-apis#796) */
|
|
249
|
+
targetGasLimit?: QUANTITY;
|
|
248
250
|
};
|
|
249
251
|
|
|
250
252
|
export type ClientVersionRpc = {
|
|
@@ -425,6 +427,7 @@ export function serializePayloadAttributes(data: PayloadAttributes): PayloadAttr
|
|
|
425
427
|
withdrawals: data.withdrawals?.map(serializeWithdrawal),
|
|
426
428
|
parentBeaconBlockRoot: data.parentBeaconBlockRoot ? bytesToData(data.parentBeaconBlockRoot) : undefined,
|
|
427
429
|
slotNumber: data.slotNumber !== undefined ? numToQuantity(data.slotNumber) : undefined,
|
|
430
|
+
targetGasLimit: data.targetGasLimit !== undefined ? numToQuantity(data.targetGasLimit) : undefined,
|
|
428
431
|
};
|
|
429
432
|
}
|
|
430
433
|
|
|
@@ -442,6 +445,7 @@ export function deserializePayloadAttributes(data: PayloadAttributesRpc): Payloa
|
|
|
442
445
|
withdrawals: data.withdrawals?.map((withdrawal) => deserializeWithdrawal(withdrawal)),
|
|
443
446
|
parentBeaconBlockRoot: data.parentBeaconBlockRoot ? dataToBytes(data.parentBeaconBlockRoot, 32) : undefined,
|
|
444
447
|
slotNumber: data.slotNumber !== undefined ? quantityToNum(data.slotNumber) : undefined,
|
|
448
|
+
targetGasLimit: data.targetGasLimit !== undefined ? quantityToNum(data.targetGasLimit) : undefined,
|
|
445
449
|
};
|
|
446
450
|
}
|
|
447
451
|
|
|
@@ -987,10 +987,11 @@ export function createLodestarMetrics(
|
|
|
987
987
|
}),
|
|
988
988
|
},
|
|
989
989
|
importPayload: {
|
|
990
|
-
|
|
991
|
-
name: "
|
|
992
|
-
help: "
|
|
990
|
+
elapsedTimeTillImported: register.histogram<{source: PayloadEnvelopeInputSource}>({
|
|
991
|
+
name: "lodestar_import_payload_elapsed_time_till_imported_seconds",
|
|
992
|
+
help: "Time elapsed between slot time and the time execution payload envelope is imported (added to fork choice)",
|
|
993
993
|
labelNames: ["source"],
|
|
994
|
+
buckets: [1, 2, 3, 6, 9, 12],
|
|
994
995
|
}),
|
|
995
996
|
columnsBySource: register.gauge<{source: PayloadEnvelopeInputSource}>({
|
|
996
997
|
name: "lodestar_import_payload_columns_by_source_total",
|
package/src/network/interface.ts
CHANGED
|
@@ -113,6 +113,7 @@ export interface INetwork extends INetworkCorePublic {
|
|
|
113
113
|
publishLightClientFinalityUpdate(update: LightClientFinalityUpdate): Promise<number>;
|
|
114
114
|
publishLightClientOptimisticUpdate(update: LightClientOptimisticUpdate): Promise<number>;
|
|
115
115
|
publishSignedExecutionPayloadEnvelope(signedEnvelope: gloas.SignedExecutionPayloadEnvelope): Promise<number>;
|
|
116
|
+
publishSignedExecutionPayloadBid(signedBid: gloas.SignedExecutionPayloadBid): Promise<number>;
|
|
116
117
|
publishPayloadAttestationMessage(payloadAttestationMessage: gloas.PayloadAttestationMessage): Promise<number>;
|
|
117
118
|
publishProposerPreferences(signedProposerPreferences: gloas.SignedProposerPreferences): Promise<number>;
|
|
118
119
|
|
package/src/network/network.ts
CHANGED
|
@@ -515,6 +515,17 @@ export class Network implements INetwork {
|
|
|
515
515
|
);
|
|
516
516
|
}
|
|
517
517
|
|
|
518
|
+
async publishSignedExecutionPayloadBid(signedBid: gloas.SignedExecutionPayloadBid): Promise<number> {
|
|
519
|
+
const epoch = computeEpochAtSlot(signedBid.message.slot);
|
|
520
|
+
const boundary = this.config.getForkBoundaryAtEpoch(epoch);
|
|
521
|
+
|
|
522
|
+
return this.publishGossip<GossipType.execution_payload_bid>(
|
|
523
|
+
{type: GossipType.execution_payload_bid, boundary},
|
|
524
|
+
signedBid,
|
|
525
|
+
{ignoreDuplicatePublishError: true}
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
|
|
518
529
|
async publishPayloadAttestationMessage(payloadAttestationMessage: gloas.PayloadAttestationMessage): Promise<number> {
|
|
519
530
|
const epoch = computeEpochAtSlot(payloadAttestationMessage.data.slot);
|
|
520
531
|
const boundary = this.config.getForkBoundaryAtEpoch(epoch);
|
|
@@ -1117,7 +1117,16 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1117
1117
|
}
|
|
1118
1118
|
|
|
1119
1119
|
const slot = envelope.payload.slotNumber;
|
|
1120
|
-
const delaySec =
|
|
1120
|
+
const delaySec = chain.clock.secFromSlot(slot, seenTimestampSec);
|
|
1121
|
+
|
|
1122
|
+
logger.debug("Received gossip payload envelope", {
|
|
1123
|
+
currentSlot: chain.clock.currentSlot,
|
|
1124
|
+
peerId: peerIdStr,
|
|
1125
|
+
slot,
|
|
1126
|
+
blockRoot: toRootHex(envelope.beaconBlockRoot),
|
|
1127
|
+
delaySec,
|
|
1128
|
+
});
|
|
1129
|
+
|
|
1121
1130
|
metrics?.gossipExecutionPayloadEnvelope.elapsedTimeTillReceived.observe({source: OpSource.gossip}, delaySec);
|
|
1122
1131
|
chain.validatorMonitor?.registerExecutionPayloadEnvelope(OpSource.gossip, delaySec, signedEnvelope);
|
|
1123
1132
|
|
|
@@ -1206,7 +1215,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1206
1215
|
chain.forkChoice.notifyPtcMessages(
|
|
1207
1216
|
toRootHex(payloadAttestationMessage.data.beaconBlockRoot),
|
|
1208
1217
|
validationResult.validatorCommitteeIndices,
|
|
1209
|
-
payloadAttestationMessage.data.payloadPresent
|
|
1218
|
+
payloadAttestationMessage.data.payloadPresent,
|
|
1219
|
+
payloadAttestationMessage.data.blobDataAvailable
|
|
1210
1220
|
);
|
|
1211
1221
|
},
|
|
1212
1222
|
[GossipType.execution_payload_bid]: async ({
|
|
@@ -1215,16 +1225,18 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1215
1225
|
}: GossipHandlerParamGeneric<GossipType.execution_payload_bid>) => {
|
|
1216
1226
|
const {serializedData} = gossipData;
|
|
1217
1227
|
const executionPayloadBid = sszDeserialize(topic, serializedData);
|
|
1218
|
-
await validateGossipExecutionPayloadBid(chain, executionPayloadBid);
|
|
1228
|
+
const {proposerIndex} = await validateGossipExecutionPayloadBid(chain, executionPayloadBid);
|
|
1219
1229
|
|
|
1220
1230
|
// Handle valid payload bid by storing in a bid pool
|
|
1221
1231
|
try {
|
|
1222
|
-
const insertOutcome = chain.executionPayloadBidPool.add(executionPayloadBid
|
|
1232
|
+
const insertOutcome = chain.executionPayloadBidPool.add(executionPayloadBid);
|
|
1223
1233
|
metrics?.opPool.executionPayloadBidPool.gossipInsertOutcome.inc({insertOutcome});
|
|
1224
1234
|
} catch (e) {
|
|
1225
1235
|
logger.error("Error adding to executionPayloadBid pool", {}, e as Error);
|
|
1226
1236
|
}
|
|
1227
1237
|
|
|
1238
|
+
chain.validatorMonitor?.registerExecutionPayloadBid(OpSource.gossip, proposerIndex, executionPayloadBid.message);
|
|
1239
|
+
|
|
1228
1240
|
chain.emitter.emit(routes.events.EventType.executionPayloadBid, {
|
|
1229
1241
|
version: config.getForkName(executionPayloadBid.message.slot),
|
|
1230
1242
|
data: executionPayloadBid,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/execution/builder/utils.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAU1F"}
|