@lodestar/beacon-node 1.44.0-dev.552cdce8d0 → 1.44.0-dev.6a52e6a9f6
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/debug/index.d.ts.map +1 -1
- package/lib/api/impl/debug/index.js +69 -12
- package/lib/api/impl/debug/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +101 -42
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/archiveStore/archiveStore.d.ts +0 -1
- package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
- package/lib/chain/archiveStore/archiveStore.js +0 -4
- package/lib/chain/archiveStore/archiveStore.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +5 -2
- 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 +5 -3
- 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 +11 -1
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +2 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/errors/payloadAttestation.d.ts +6 -0
- package/lib/chain/errors/payloadAttestation.d.ts.map +1 -1
- package/lib/chain/errors/payloadAttestation.js +1 -0
- package/lib/chain/errors/payloadAttestation.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/regen/interface.d.ts +2 -1
- package/lib/chain/regen/interface.d.ts.map +1 -1
- package/lib/chain/regen/interface.js +2 -0
- package/lib/chain/regen/interface.js.map +1 -1
- package/lib/chain/regen/queued.d.ts +0 -1
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +0 -4
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts +0 -5
- package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
- package/lib/chain/stateCache/fifoBlockStateCache.js +0 -5
- package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +1 -4
- package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
- package/lib/chain/stateCache/persistentCheckpointsCache.js +5 -2
- package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
- package/lib/chain/stateCache/types.d.ts +0 -2
- package/lib/chain/stateCache/types.d.ts.map +1 -1
- package/lib/chain/stateCache/types.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 +58 -15
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +24 -4
- package/lib/chain/validation/payloadAttestationMessage.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/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +5 -0
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +3 -3
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts +2 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +15 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
- package/lib/network/reqresp/handlers/index.js +2 -2
- package/lib/network/reqresp/handlers/index.js.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts.map +1 -1
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js +22 -3
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
- package/package.json +14 -16
- package/src/api/impl/beacon/blocks/index.ts +36 -0
- package/src/api/impl/beacon/pool/index.ts +3 -1
- package/src/api/impl/debug/index.ts +73 -12
- package/src/api/impl/validator/index.ts +112 -43
- package/src/chain/archiveStore/archiveStore.ts +0 -5
- package/src/chain/blocks/importBlock.ts +10 -2
- package/src/chain/blocks/importExecutionPayload.ts +8 -2
- package/src/chain/chain.ts +2 -0
- package/src/chain/errors/executionPayloadBid.ts +6 -1
- package/src/chain/errors/payloadAttestation.ts +2 -0
- 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/regen/interface.ts +2 -1
- package/src/chain/regen/queued.ts +0 -5
- package/src/chain/stateCache/fifoBlockStateCache.ts +0 -6
- package/src/chain/stateCache/persistentCheckpointsCache.ts +6 -2
- package/src/chain/stateCache/types.ts +0 -2
- package/src/chain/validation/executionPayloadBid.ts +66 -19
- package/src/chain/validation/payloadAttestationMessage.ts +26 -4
- 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 +17 -4
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +6 -0
- package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +1 -1
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +3 -3
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +20 -1
- package/src/network/reqresp/handlers/index.ts +2 -2
- package/src/network/reqresp/utils/dataColumnResponseValidation.ts +21 -3
- 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
|
@@ -8,6 +8,7 @@ import {RootHex, gloas, ssz} from "@lodestar/types";
|
|
|
8
8
|
import {toRootHex} from "@lodestar/utils";
|
|
9
9
|
import {GossipAction, PayloadAttestationError, PayloadAttestationErrorCode} from "../errors/index.js";
|
|
10
10
|
import {IBeaconChain} from "../index.js";
|
|
11
|
+
import {RegenCaller} from "../regen/index.js";
|
|
11
12
|
|
|
12
13
|
export type PayloadAttestationValidationResult = {
|
|
13
14
|
attDataRootHex: RootHex;
|
|
@@ -61,22 +62,43 @@ async function validatePayloadAttestationMessage(
|
|
|
61
62
|
// [IGNORE] The message's block `data.beacon_block_root` has been seen (via
|
|
62
63
|
// gossip or non-gossip sources) (a client MAY queue attestation for processing
|
|
63
64
|
// once the block is retrieved. Note a client might want to request payload after).
|
|
64
|
-
|
|
65
|
+
const block = chain.forkChoice.getBlockDefaultStatus(data.beaconBlockRoot);
|
|
66
|
+
if (!block) {
|
|
65
67
|
throw new PayloadAttestationError(GossipAction.IGNORE, {
|
|
66
68
|
code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
67
69
|
blockRoot: toRootHex(data.beaconBlockRoot),
|
|
68
70
|
});
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
// [IGNORE] The block referenced by `data.beacon_block_root` is at slot `data.slot`,
|
|
74
|
+
// i.e. the block has `block.slot == data.slot`.
|
|
75
|
+
if (block.slot !== data.slot) {
|
|
76
|
+
throw new PayloadAttestationError(GossipAction.IGNORE, {
|
|
77
|
+
code: PayloadAttestationErrorCode.INVALID_BLOCK_SLOT,
|
|
78
|
+
blockRoot: toRootHex(data.beaconBlockRoot),
|
|
79
|
+
blockSlot: block.slot,
|
|
80
|
+
slot: data.slot,
|
|
81
|
+
});
|
|
74
82
|
}
|
|
75
83
|
|
|
76
84
|
// [REJECT] The message's block `data.beacon_block_root` passes validation.
|
|
77
85
|
// TODO GLOAS: implement this. Technically if we cannot get proto block from fork choice,
|
|
78
86
|
// it is possible that the block didn't pass the validation
|
|
79
87
|
|
|
88
|
+
// Use the referenced block's branch state for the PTC committee check
|
|
89
|
+
const state = await chain.regen
|
|
90
|
+
.getBlockSlotState(block, data.slot, {dontTransferCache: true}, RegenCaller.validateGossipPayloadAttestationMessage)
|
|
91
|
+
.catch(() => {
|
|
92
|
+
throw new PayloadAttestationError(GossipAction.IGNORE, {
|
|
93
|
+
code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
94
|
+
blockRoot: toRootHex(data.beaconBlockRoot),
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (!isStatePostGloas(state)) {
|
|
99
|
+
throw new Error(`Expected gloas+ state for payload attestation validation, got fork=${state.forkName}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
80
102
|
// [REJECT] The message's validator index is within the payload committee in
|
|
81
103
|
// `get_ptc(state, data.slot)`. The `state` is the head state corresponding to
|
|
82
104
|
// processing the block up to the current slot as determined by the fork choice.
|
|
@@ -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
|
|
|
@@ -1205,8 +1214,10 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1205
1214
|
}
|
|
1206
1215
|
chain.forkChoice.notifyPtcMessages(
|
|
1207
1216
|
toRootHex(payloadAttestationMessage.data.beaconBlockRoot),
|
|
1217
|
+
payloadAttestationMessage.data.slot,
|
|
1208
1218
|
validationResult.validatorCommitteeIndices,
|
|
1209
|
-
payloadAttestationMessage.data.payloadPresent
|
|
1219
|
+
payloadAttestationMessage.data.payloadPresent,
|
|
1220
|
+
payloadAttestationMessage.data.blobDataAvailable
|
|
1210
1221
|
);
|
|
1211
1222
|
},
|
|
1212
1223
|
[GossipType.execution_payload_bid]: async ({
|
|
@@ -1215,16 +1226,18 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1215
1226
|
}: GossipHandlerParamGeneric<GossipType.execution_payload_bid>) => {
|
|
1216
1227
|
const {serializedData} = gossipData;
|
|
1217
1228
|
const executionPayloadBid = sszDeserialize(topic, serializedData);
|
|
1218
|
-
await validateGossipExecutionPayloadBid(chain, executionPayloadBid);
|
|
1229
|
+
const {proposerIndex} = await validateGossipExecutionPayloadBid(chain, executionPayloadBid);
|
|
1219
1230
|
|
|
1220
1231
|
// Handle valid payload bid by storing in a bid pool
|
|
1221
1232
|
try {
|
|
1222
|
-
const insertOutcome = chain.executionPayloadBidPool.add(executionPayloadBid
|
|
1233
|
+
const insertOutcome = chain.executionPayloadBidPool.add(executionPayloadBid);
|
|
1223
1234
|
metrics?.opPool.executionPayloadBidPool.gossipInsertOutcome.inc({insertOutcome});
|
|
1224
1235
|
} catch (e) {
|
|
1225
1236
|
logger.error("Error adding to executionPayloadBid pool", {}, e as Error);
|
|
1226
1237
|
}
|
|
1227
1238
|
|
|
1239
|
+
chain.validatorMonitor?.registerExecutionPayloadBid(OpSource.gossip, proposerIndex, executionPayloadBid.message);
|
|
1240
|
+
|
|
1228
1241
|
chain.emitter.emit(routes.events.EventType.executionPayloadBid, {
|
|
1229
1242
|
version: config.getForkName(executionPayloadBid.message.slot),
|
|
1230
1243
|
data: executionPayloadBid,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {PeerId} from "@libp2p/interface";
|
|
2
2
|
import {ChainConfig} from "@lodestar/config";
|
|
3
|
+
import {PayloadStatus} from "@lodestar/fork-choice";
|
|
3
4
|
import {ForkSeq, GENESIS_SLOT} from "@lodestar/params";
|
|
4
5
|
import {RespStatus, ResponseError, ResponseOutgoing} from "@lodestar/reqresp";
|
|
5
6
|
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
@@ -104,6 +105,11 @@ export async function* onDataColumnSidecarsByRange(
|
|
|
104
105
|
|
|
105
106
|
// Must include only columns in the range requested
|
|
106
107
|
if (block.slot > archiveMaxSlot && block.slot >= startSlot && block.slot < endSlot) {
|
|
108
|
+
// Post-gloas, columns exist only for FULL blocks (pre-gloas blocks are always FULL)
|
|
109
|
+
if (block.payloadStatus !== PayloadStatus.FULL) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
107
113
|
// Note: Here the forkChoice head may change due to a re-org, so the headChain reflects the canonical chain
|
|
108
114
|
// at the time of the start of the request. Spec is clear the chain of columns must be consistent, but on
|
|
109
115
|
// re-org there's no need to abort the request
|
|
@@ -30,7 +30,7 @@ export async function* onDataColumnSidecarsByRoot(
|
|
|
30
30
|
const {blockRoot, columns: requestedColumns} = dataColumnsByRootIdentifier;
|
|
31
31
|
const availableColumns = validateRequestedDataColumns(chain, requestedColumns);
|
|
32
32
|
if (availableColumns.length === 0) {
|
|
33
|
-
|
|
33
|
+
continue;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
const blockRootHex = toRootHex(blockRoot);
|
|
@@ -20,9 +20,9 @@ export async function* onExecutionPayloadEnvelopesByRange(
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
const finalized = db.executionPayloadEnvelopeArchive;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
// in the next finalization run
|
|
23
|
+
// Use the finalized block's actual slot as the checkpoint epoch-boundary slot may be skipped
|
|
24
|
+
const finalizedSlot = chain.forkChoice.getFinalizedBlock().slot;
|
|
25
|
+
// The finalized block's envelope stays in the hot db until the next finalization run
|
|
26
26
|
const archiveMaxSlot = finalizedSlot - 1;
|
|
27
27
|
|
|
28
28
|
// Finalized range of envelopes
|
|
@@ -1,14 +1,18 @@
|
|
|
1
|
+
import {PeerId} from "@libp2p/interface";
|
|
1
2
|
import {ResponseOutgoing} from "@lodestar/reqresp";
|
|
2
3
|
import {computeEpochAtSlot} from "@lodestar/state-transition";
|
|
3
4
|
import {toRootHex} from "@lodestar/utils";
|
|
4
5
|
import {IBeaconChain} from "../../../chain/index.js";
|
|
5
6
|
import {IBeaconDb} from "../../../db/index.js";
|
|
6
7
|
import {ExecutionPayloadEnvelopesByRootRequest} from "../../../util/types.js";
|
|
8
|
+
import {prettyPrintPeerId} from "../../util.js";
|
|
7
9
|
|
|
8
10
|
export async function* onExecutionPayloadEnvelopesByRoot(
|
|
9
11
|
requestBody: ExecutionPayloadEnvelopesByRootRequest,
|
|
10
12
|
chain: IBeaconChain,
|
|
11
|
-
db: IBeaconDb
|
|
13
|
+
db: IBeaconDb,
|
|
14
|
+
peerId: PeerId,
|
|
15
|
+
peerClient: string
|
|
12
16
|
): AsyncIterable<ResponseOutgoing> {
|
|
13
17
|
// The gloas req/resp spec uses MIN_EPOCHS_FOR_BLOCK_REQUESTS to define the minimum range peers MUST serve.
|
|
14
18
|
// Archival nodes may still serve older retained payloads to allow genesis sync.
|
|
@@ -20,6 +24,14 @@ export async function* onExecutionPayloadEnvelopesByRoot(
|
|
|
20
24
|
const slot = block ? block.slot : await db.blockArchive.getSlotByRoot(root);
|
|
21
25
|
|
|
22
26
|
if (slot === null) {
|
|
27
|
+
chain.logger.debug(
|
|
28
|
+
"Cannot serve ExecutionPayloadEnvelopesByRoot: block root not in fork choice or block archive",
|
|
29
|
+
{
|
|
30
|
+
root: rootHex,
|
|
31
|
+
peer: prettyPrintPeerId(peerId),
|
|
32
|
+
client: peerClient,
|
|
33
|
+
}
|
|
34
|
+
);
|
|
23
35
|
continue;
|
|
24
36
|
}
|
|
25
37
|
|
|
@@ -29,6 +41,13 @@ export async function* onExecutionPayloadEnvelopesByRoot(
|
|
|
29
41
|
data: envelopeBytes,
|
|
30
42
|
boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(slot)),
|
|
31
43
|
};
|
|
44
|
+
} else {
|
|
45
|
+
chain.logger.debug("Cannot serve ExecutionPayloadEnvelopesByRoot: envelope not found", {
|
|
46
|
+
slot,
|
|
47
|
+
root: rootHex,
|
|
48
|
+
peer: prettyPrintPeerId(peerId),
|
|
49
|
+
client: peerClient,
|
|
50
|
+
});
|
|
32
51
|
}
|
|
33
52
|
}
|
|
34
53
|
}
|
|
@@ -70,9 +70,9 @@ export function getReqRespHandlers({db, chain}: {db: IBeaconDb; chain: IBeaconCh
|
|
|
70
70
|
return onDataColumnSidecarsByRoot(body, chain, db, peerId, peerClient);
|
|
71
71
|
},
|
|
72
72
|
|
|
73
|
-
[ReqRespMethod.ExecutionPayloadEnvelopesByRoot]: (req) => {
|
|
73
|
+
[ReqRespMethod.ExecutionPayloadEnvelopesByRoot]: (req, peerId, peerClient) => {
|
|
74
74
|
const body = ExecutionPayloadEnvelopesByRootRequestType(chain.config).deserialize(req.data);
|
|
75
|
-
return onExecutionPayloadEnvelopesByRoot(body, chain, db);
|
|
75
|
+
return onExecutionPayloadEnvelopesByRoot(body, chain, db, peerId, peerClient);
|
|
76
76
|
},
|
|
77
77
|
[ReqRespMethod.ExecutionPayloadEnvelopesByRange]: (req) => {
|
|
78
78
|
const body = ssz.gloas.ExecutionPayloadEnvelopesByRangeRequest.deserialize(req.data);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {LogData} from "@lodestar/logger";
|
|
2
|
+
import {ForkSeq} from "@lodestar/params";
|
|
2
3
|
import {RespStatus, ResponseError} from "@lodestar/reqresp";
|
|
3
4
|
import {ColumnIndex, Slot} from "@lodestar/types";
|
|
4
5
|
import {prettyBytes, prettyPrintIndices, toRootHex} from "@lodestar/utils";
|
|
@@ -38,6 +39,13 @@ export async function handleColumnSidecarUnavailability({
|
|
|
38
39
|
|
|
39
40
|
chain.logger.debug("dataColumnSidecar requested unavailable", logData);
|
|
40
41
|
|
|
42
|
+
// Post-gloas, columns exist only for FULL blocks; a finalized block is FULL if its envelope was
|
|
43
|
+
// archived. Bid blobsCount is unreliable here since an EMPTY block's bid may still commit to blobs
|
|
44
|
+
if (blockRoot === undefined && chain.config.getForkSeq(slot) >= ForkSeq.gloas) {
|
|
45
|
+
const envelopeBytes = await db.executionPayloadEnvelopeArchive.getBinary(slot);
|
|
46
|
+
if (!envelopeBytes) return;
|
|
47
|
+
}
|
|
48
|
+
|
|
41
49
|
const blockBytes = blockRoot ? await db.block.getBinary(blockRoot) : await db.blockArchive.getBinary(slot);
|
|
42
50
|
if (!blockBytes) {
|
|
43
51
|
chain.logger.verbose(
|
|
@@ -71,9 +79,19 @@ export function validateRequestedDataColumns(chain: IBeaconChain, requestedColum
|
|
|
71
79
|
throw new ResponseError(RespStatus.INVALID_REQUEST, "dataColumnSidecar requested without column indices");
|
|
72
80
|
}
|
|
73
81
|
|
|
74
|
-
const custodyColumns = chain.custodyConfig
|
|
75
|
-
const availableColumns =
|
|
76
|
-
const missingColumns =
|
|
82
|
+
const {custodyColumns, custodyColumnsIndex} = chain.custodyConfig;
|
|
83
|
+
const availableColumns: ColumnIndex[] = [];
|
|
84
|
+
const missingColumns: ColumnIndex[] = [];
|
|
85
|
+
for (const c of requestedColumns) {
|
|
86
|
+
// `c` is peer-controlled and SSZ-deserialized as `uint64`, so it may exceed
|
|
87
|
+
// `NUMBER_OF_COLUMNS - 1`; `Uint8Array` returns `undefined` for OOB reads,
|
|
88
|
+
// and `undefined !== 0` would silently classify OOB indices as custodied.
|
|
89
|
+
if ((custodyColumnsIndex[c] ?? 0) !== 0) {
|
|
90
|
+
availableColumns.push(c);
|
|
91
|
+
} else {
|
|
92
|
+
missingColumns.push(c);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
77
95
|
|
|
78
96
|
if (missingColumns.length > 0) {
|
|
79
97
|
chain.logger.verbose("Requested dataColumnSidecar for non-custody columns", {
|
|
@@ -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"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* From https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md
|
|
3
|
-
*/
|
|
4
|
-
const gasLimitAdjustmentFactor = 1024;
|
|
5
|
-
/**
|
|
6
|
-
* Calculates expected gas limit based on parent gas limit and target gas limit
|
|
7
|
-
*/
|
|
8
|
-
export function getExpectedGasLimit(parentGasLimit, targetGasLimit) {
|
|
9
|
-
const maxGasLimitDifference = Math.max(Math.floor(parentGasLimit / gasLimitAdjustmentFactor) - 1, 0);
|
|
10
|
-
if (targetGasLimit > parentGasLimit) {
|
|
11
|
-
const gasDiff = targetGasLimit - parentGasLimit;
|
|
12
|
-
return parentGasLimit + Math.min(gasDiff, maxGasLimitDifference);
|
|
13
|
-
}
|
|
14
|
-
const gasDiff = parentGasLimit - targetGasLimit;
|
|
15
|
-
return parentGasLimit - Math.min(gasDiff, maxGasLimitDifference);
|
|
16
|
-
}
|
|
17
|
-
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../src/execution/builder/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAEtC;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,cAAsB,EAAE,cAAsB,EAAU;IAC1F,MAAM,qBAAqB,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,wBAAwB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IAErG,IAAI,cAAc,GAAG,cAAc,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,cAAc,GAAG,cAAc,CAAC;QAChD,OAAO,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;IACnE,CAAC;IAED,MAAM,OAAO,GAAG,cAAc,GAAG,cAAc,CAAC;IAChD,OAAO,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,qBAAqB,CAAC,CAAC;AAAA,CAClE"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* From https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md
|
|
3
|
-
*/
|
|
4
|
-
const gasLimitAdjustmentFactor = 1024;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Calculates expected gas limit based on parent gas limit and target gas limit
|
|
8
|
-
*/
|
|
9
|
-
export function getExpectedGasLimit(parentGasLimit: number, targetGasLimit: number): number {
|
|
10
|
-
const maxGasLimitDifference = Math.max(Math.floor(parentGasLimit / gasLimitAdjustmentFactor) - 1, 0);
|
|
11
|
-
|
|
12
|
-
if (targetGasLimit > parentGasLimit) {
|
|
13
|
-
const gasDiff = targetGasLimit - parentGasLimit;
|
|
14
|
-
return parentGasLimit + Math.min(gasDiff, maxGasLimitDifference);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const gasDiff = parentGasLimit - targetGasLimit;
|
|
18
|
-
return parentGasLimit - Math.min(gasDiff, maxGasLimitDifference);
|
|
19
|
-
}
|