@lodestar/beacon-node 1.44.0-dev.6ef8199cfa → 1.44.0-dev.762dd5f186
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 +66 -33
- 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 -26
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/config/constants.d.ts +5 -0
- package/lib/api/impl/config/constants.d.ts.map +1 -1
- package/lib/api/impl/config/constants.js +6 -1
- package/lib/api/impl/config/constants.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/lodestar/index.d.ts.map +1 -1
- package/lib/api/impl/lodestar/index.js +28 -0
- package/lib/api/impl/lodestar/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +117 -72
- 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 +19 -4
- 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/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +3 -3
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
- package/lib/chain/chain.d.ts +3 -3
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +11 -3
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +2 -1
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js.map +1 -1
- package/lib/chain/errors/blockError.d.ts +0 -7
- package/lib/chain/errors/blockError.d.ts.map +1 -1
- package/lib/chain/errors/blockError.js +0 -3
- package/lib/chain/errors/blockError.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +23 -1
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +4 -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 +4 -4
- package/lib/chain/forkChoice/index.d.ts.map +1 -1
- package/lib/chain/forkChoice/index.js +24 -11
- package/lib/chain/forkChoice/index.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -2
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.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/options.d.ts.map +1 -1
- package/lib/chain/options.js +1 -0
- package/lib/chain/options.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +2 -10
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +4 -2
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +81 -27
- 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/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +8 -2
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.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/block.d.ts +5 -1
- package/lib/chain/validation/block.d.ts.map +1 -1
- package/lib/chain/validation/block.js +4 -14
- package/lib/chain/validation/block.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 +81 -16
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/executionPayloadEnvelope.js +1 -3
- package/lib/chain/validation/executionPayloadEnvelope.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/http.js +1 -1
- package/lib/execution/engine/http.js.map +1 -1
- package/lib/execution/engine/interface.d.ts +2 -2
- package/lib/execution/engine/interface.d.ts.map +1 -1
- package/lib/execution/engine/interface.js +6 -2
- package/lib/execution/engine/interface.js.map +1 -1
- package/lib/execution/engine/mock.d.ts.map +1 -1
- package/lib/execution/engine/mock.js +3 -5
- package/lib/execution/engine/mock.js.map +1 -1
- package/lib/execution/engine/types.d.ts +15 -7
- package/lib/execution/engine/types.d.ts.map +1 -1
- package/lib/execution/engine/types.js +47 -9
- package/lib/execution/engine/types.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +5 -1
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +14 -3
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +770 -3
- package/lib/network/gossip/topic.d.ts.map +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 +21 -6
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/index.d.ts +2 -2
- package/lib/network/processor/index.d.ts.map +1 -1
- package/lib/network/processor/index.js +25 -23
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js +9 -5
- package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +13 -3
- 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.d.ts +2 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +16 -6
- 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 +4 -4
- 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 +23 -5
- package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
- package/lib/sync/types.d.ts +9 -1
- package/lib/sync/types.d.ts.map +1 -1
- package/lib/sync/types.js +9 -2
- package/lib/sync/types.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +64 -30
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/util/dataColumns.d.ts.map +1 -1
- package/lib/util/dataColumns.js +16 -11
- package/lib/util/dataColumns.js.map +1 -1
- package/lib/util/sszBytes.js +1 -1
- package/package.json +15 -17
- package/src/api/impl/beacon/blocks/index.ts +76 -42
- package/src/api/impl/beacon/pool/index.ts +4 -42
- package/src/api/impl/config/constants.ts +10 -0
- package/src/api/impl/debug/index.ts +73 -12
- package/src/api/impl/lodestar/index.ts +30 -0
- package/src/api/impl/validator/index.ts +137 -86
- package/src/chain/archiveStore/archiveStore.ts +0 -5
- package/src/chain/blocks/importBlock.ts +29 -7
- package/src/chain/blocks/importExecutionPayload.ts +8 -2
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +3 -5
- package/src/chain/chain.ts +14 -4
- package/src/chain/emitter.ts +3 -2
- package/src/chain/errors/blockError.ts +0 -4
- package/src/chain/errors/executionPayloadBid.ts +20 -1
- package/src/chain/errors/payloadAttestation.ts +2 -0
- package/src/chain/forkChoice/index.ts +27 -4
- package/src/chain/interface.ts +1 -2
- package/src/chain/opPools/executionPayloadBidPool.ts +10 -9
- package/src/chain/options.ts +1 -0
- package/src/chain/prepareNextSlot.ts +2 -11
- package/src/chain/produceBlock/produceBlockBody.ts +114 -40
- package/src/chain/regen/interface.ts +2 -1
- package/src/chain/regen/queued.ts +0 -5
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +8 -3
- 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/block.ts +12 -16
- package/src/chain/validation/executionPayloadBid.ts +90 -19
- package/src/chain/validation/executionPayloadEnvelope.ts +1 -3
- 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/http.ts +1 -1
- package/src/execution/engine/interface.ts +12 -2
- package/src/execution/engine/mock.ts +6 -5
- package/src/execution/engine/types.ts +75 -14
- package/src/metrics/metrics/lodestar.ts +15 -3
- package/src/network/interface.ts +1 -0
- package/src/network/network.ts +11 -0
- package/src/network/processor/gossipHandlers.ts +26 -6
- package/src/network/processor/index.ts +27 -27
- package/src/network/reqresp/handlers/beaconBlocksByRange.ts +12 -5
- package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -3
- package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +1 -1
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +22 -6
- package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +20 -1
- package/src/network/reqresp/handlers/index.ts +4 -4
- package/src/network/reqresp/utils/dataColumnResponseValidation.ts +22 -5
- package/src/sync/types.ts +11 -2
- package/src/sync/unknownBlock.ts +70 -31
- package/src/util/dataColumns.ts +17 -12
- package/src/util/sszBytes.ts +1 -1
- 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
|
@@ -15,12 +15,17 @@ import {BlockErrorCode, BlockGossipError, GossipAction} from "../errors/index.js
|
|
|
15
15
|
import {IBeaconChain} from "../interface.js";
|
|
16
16
|
import {RegenCaller} from "../regen/index.js";
|
|
17
17
|
|
|
18
|
+
export type GossipBlockValidationResult = {
|
|
19
|
+
/** Number of skipped slots between the block and its parent (blockSlot - parentSlot - 1) */
|
|
20
|
+
skippedSlots: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
18
23
|
export async function validateGossipBlock(
|
|
19
24
|
config: ChainForkConfig,
|
|
20
25
|
chain: IBeaconChain,
|
|
21
26
|
signedBlock: SignedBeaconBlock,
|
|
22
27
|
fork: ForkName
|
|
23
|
-
): Promise<
|
|
28
|
+
): Promise<GossipBlockValidationResult> {
|
|
24
29
|
const block = signedBlock.message;
|
|
25
30
|
const blockSlot = block.slot;
|
|
26
31
|
const blockEpoch = computeEpochAtSlot(blockSlot);
|
|
@@ -109,21 +114,6 @@ export async function validateGossipBlock(
|
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
116
|
|
|
112
|
-
// [IGNORE] The attestation head block is too far behind the attestation slot, causing many skip slots.
|
|
113
|
-
// This is deemed a DoS risk because we need to get the proposerShuffling. To get the shuffling we have
|
|
114
|
-
// to do a bunch of epoch transitions, the longer the distance between the parent and block,
|
|
115
|
-
// the more we have to do. epochTransitions are expensive ~750ms, so we must limit how many a
|
|
116
|
-
// single bad block can trigger
|
|
117
|
-
// Note: Ensure this check is done before calling chain.regen.getBlockSlotStat as this is the function that does various epoch transitions.
|
|
118
|
-
// Note: This validation check is not part of the spec.
|
|
119
|
-
if (chain.opts.maxSkipSlots != null && parentBlock.slot + chain.opts.maxSkipSlots < blockSlot) {
|
|
120
|
-
throw new BlockGossipError(GossipAction.IGNORE, {
|
|
121
|
-
code: BlockErrorCode.TOO_MANY_SKIPPED_SLOTS,
|
|
122
|
-
parentSlot: parentBlock.slot,
|
|
123
|
-
blockSlot,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
117
|
// [REJECT] The block is from a higher slot than its parent.
|
|
128
118
|
if (parentBlock.slot >= blockSlot) {
|
|
129
119
|
throw new BlockGossipError(GossipAction.REJECT, {
|
|
@@ -133,6 +123,10 @@ export async function validateGossipBlock(
|
|
|
133
123
|
});
|
|
134
124
|
}
|
|
135
125
|
|
|
126
|
+
// Number of skipped slots between block and parent (non-spec). Previously this gated blocks via
|
|
127
|
+
// maxSkipSlots; now the caller only observes it so legitimate post-skip blocks are no longer ignored.
|
|
128
|
+
const skippedSlots = blockSlot - parentBlock.slot - 1;
|
|
129
|
+
|
|
136
130
|
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in Consensus Layer -- i.e. validate that len(body.signed_beacon_block.message.blob_kzg_commitments) <= MAX_BLOBS_PER_BLOCK
|
|
137
131
|
if (isForkPostDeneb(fork) && !isForkPostGloas(fork)) {
|
|
138
132
|
const blobKzgCommitmentsLen = (block as deneb.BeaconBlock).body.blobKzgCommitments.length;
|
|
@@ -247,4 +241,6 @@ export async function validateGossipBlock(
|
|
|
247
241
|
}
|
|
248
242
|
|
|
249
243
|
chain.seenBlockProposers.add(blockSlot, proposerIndex);
|
|
244
|
+
|
|
245
|
+
return {skippedSlots};
|
|
250
246
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import {PublicKey} from "@chainsafe/blst";
|
|
2
|
+
import {PAYLOAD_BUILDER_VERSION} from "@lodestar/params";
|
|
2
3
|
import {
|
|
3
4
|
computeEpochAtSlot,
|
|
4
5
|
createSingleSignatureSetFromComponents,
|
|
5
6
|
getExecutionPayloadBidSigningRoot,
|
|
6
7
|
isActiveBuilder,
|
|
8
|
+
isGasLimitTargetCompatible,
|
|
7
9
|
isStatePostGloas,
|
|
8
10
|
} from "@lodestar/state-transition";
|
|
9
|
-
import {gloas} from "@lodestar/types";
|
|
11
|
+
import {ValidatorIndex, gloas} from "@lodestar/types";
|
|
10
12
|
import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
|
|
11
13
|
import {getShufflingDependentRoot} from "../../util/dependentRoot.js";
|
|
12
14
|
import {ExecutionPayloadBidError, ExecutionPayloadBidErrorCode, GossipAction} from "../errors/index.js";
|
|
@@ -16,28 +18,24 @@ import {RegenCaller} from "../regen/index.js";
|
|
|
16
18
|
export async function validateApiExecutionPayloadBid(
|
|
17
19
|
chain: IBeaconChain,
|
|
18
20
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
19
|
-
): Promise<
|
|
21
|
+
): Promise<{proposerIndex: ValidatorIndex}> {
|
|
20
22
|
return validateExecutionPayloadBid(chain, signedExecutionPayloadBid);
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
export async function validateGossipExecutionPayloadBid(
|
|
24
26
|
chain: IBeaconChain,
|
|
25
27
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
26
|
-
): Promise<
|
|
28
|
+
): Promise<{proposerIndex: ValidatorIndex}> {
|
|
27
29
|
return validateExecutionPayloadBid(chain, signedExecutionPayloadBid);
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
async function validateExecutionPayloadBid(
|
|
31
33
|
chain: IBeaconChain,
|
|
32
34
|
signedExecutionPayloadBid: gloas.SignedExecutionPayloadBid
|
|
33
|
-
): Promise<
|
|
35
|
+
): Promise<{proposerIndex: ValidatorIndex}> {
|
|
34
36
|
const bid = signedExecutionPayloadBid.message;
|
|
35
37
|
const parentBlockRootHex = toRootHex(bid.parentBlockRoot);
|
|
36
38
|
const parentBlockHashHex = toRootHex(bid.parentBlockHash);
|
|
37
|
-
const state = await chain.getHeadStateAtCurrentEpoch(RegenCaller.validateGossipExecutionPayloadBid);
|
|
38
|
-
if (!isStatePostGloas(state)) {
|
|
39
|
-
throw new Error(`Expected gloas+ state for execution payload bid validation, got fork=${state.forkName}`);
|
|
40
|
-
}
|
|
41
39
|
|
|
42
40
|
// [IGNORE] `bid.slot` is the current slot or the next slot.
|
|
43
41
|
const currentSlot = chain.clock.currentSlot;
|
|
@@ -60,6 +58,17 @@ async function validateExecutionPayloadBid(
|
|
|
60
58
|
});
|
|
61
59
|
}
|
|
62
60
|
|
|
61
|
+
// [REJECT] The bid is for a higher slot than its parent block -- i.e.
|
|
62
|
+
// validate that `bid.slot` is greater than the slot of the block with root
|
|
63
|
+
// `bid.parent_block_root`.
|
|
64
|
+
if (bid.slot <= parentBlock.slot) {
|
|
65
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
66
|
+
code: ExecutionPayloadBidErrorCode.NOT_LATER_THAN_PARENT,
|
|
67
|
+
parentSlot: parentBlock.slot,
|
|
68
|
+
slot: bid.slot,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
63
72
|
// [IGNORE] A `SignedProposerPreferences` matching `bid.slot` and the bid's branch has been
|
|
64
73
|
// seen — i.e. `proposal_slot == bid.slot` AND `dependent_root ==
|
|
65
74
|
// get_proposer_dependent_root(parent_state, compute_epoch_at_slot(bid.slot))`.
|
|
@@ -99,9 +108,31 @@ async function validateExecutionPayloadBid(
|
|
|
99
108
|
});
|
|
100
109
|
}
|
|
101
110
|
|
|
111
|
+
// Use the bid's parent branch state for builder checks
|
|
112
|
+
const state = await chain.regen
|
|
113
|
+
.getBlockSlotState(parentBlock, bid.slot, {dontTransferCache: true}, RegenCaller.validateGossipExecutionPayloadBid)
|
|
114
|
+
.catch(() => {
|
|
115
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
116
|
+
code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
117
|
+
parentBlockRoot: parentBlockRootHex,
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (!isStatePostGloas(state)) {
|
|
122
|
+
throw new Error(`Expected gloas+ state for execution payload bid validation, got fork=${state.forkName}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
102
125
|
// [REJECT] `bid.builder_index` is a valid/active builder index -- i.e.
|
|
103
126
|
// `is_active_builder(state, bid.builder_index)` returns `True`.
|
|
104
|
-
|
|
127
|
+
let builder: gloas.Builder;
|
|
128
|
+
try {
|
|
129
|
+
builder = state.getBuilder(bid.builderIndex);
|
|
130
|
+
} catch {
|
|
131
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
132
|
+
code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE,
|
|
133
|
+
builderIndex: bid.builderIndex,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
105
136
|
if (!isActiveBuilder(builder, state.finalizedCheckpoint.epoch)) {
|
|
106
137
|
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
107
138
|
code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE,
|
|
@@ -109,6 +140,17 @@ async function validateExecutionPayloadBid(
|
|
|
109
140
|
});
|
|
110
141
|
}
|
|
111
142
|
|
|
143
|
+
// [REJECT] The builder version is `PAYLOAD_BUILDER_VERSION` -- i.e.
|
|
144
|
+
// `state.builders[bid.builder_index].version == PAYLOAD_BUILDER_VERSION`.
|
|
145
|
+
if (builder.version !== PAYLOAD_BUILDER_VERSION) {
|
|
146
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
147
|
+
code: ExecutionPayloadBidErrorCode.INVALID_BUILDER_VERSION,
|
|
148
|
+
builderIndex: bid.builderIndex,
|
|
149
|
+
version: builder.version,
|
|
150
|
+
expectedVersion: PAYLOAD_BUILDER_VERSION,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
112
154
|
// [REJECT] `bid.execution_payment` is zero.
|
|
113
155
|
if (bid.executionPayment !== 0) {
|
|
114
156
|
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
@@ -128,14 +170,33 @@ async function validateExecutionPayloadBid(
|
|
|
128
170
|
});
|
|
129
171
|
}
|
|
130
172
|
|
|
131
|
-
// [
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
173
|
+
// [IGNORE] `bid.parent_block_hash` is the block hash of a known execution payload in fork
|
|
174
|
+
// choice. Looks up the variant of `bid.parent_block_root` whose payload hash matches
|
|
175
|
+
// `bid.parent_block_hash` — works for both FULL parents (FULL variant carries the delivered
|
|
176
|
+
// payload's hash) and EMPTY parents (EMPTY/PENDING variants carry the inherited parent
|
|
177
|
+
// payload's hash, since the new block doesn't have its own payload). Variant carries the
|
|
178
|
+
// executed payload's gas_limit, which we use as `parent_gas_limit` below.
|
|
179
|
+
const parentPayloadVariant = chain.forkChoice.getBlockHexAndBlockHash(parentBlockRootHex, parentBlockHashHex);
|
|
180
|
+
if (parentPayloadVariant === null || parentPayloadVariant.executionPayloadBlockHash === null) {
|
|
181
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
182
|
+
code: ExecutionPayloadBidErrorCode.UNKNOWN_PARENT_BLOCK_HASH,
|
|
183
|
+
parentBlockHash: parentBlockHashHex,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// [IGNORE] `is_gas_limit_target_compatible(parent_gas_limit, bid.gas_limit, target_gas_limit)`,
|
|
188
|
+
// where `parent_gas_limit` is the `gas_limit` of the parent execution payload and
|
|
189
|
+
// `target_gas_limit` is `proposer_preferences.target_gas_limit`.
|
|
190
|
+
const bidGasLimit = bid.gasLimit;
|
|
191
|
+
const parentGasLimit = parentPayloadVariant.executionPayloadGasLimit;
|
|
192
|
+
const targetGasLimit = proposerPreferences.message.targetGasLimit;
|
|
193
|
+
if (!isGasLimitTargetCompatible(parentGasLimit, bidGasLimit, targetGasLimit)) {
|
|
194
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
135
195
|
code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_GAS_LIMIT_MISMATCH,
|
|
136
196
|
builderIndex: bid.builderIndex,
|
|
137
197
|
bidGasLimit,
|
|
138
|
-
|
|
198
|
+
parentGasLimit,
|
|
199
|
+
targetGasLimit,
|
|
139
200
|
});
|
|
140
201
|
}
|
|
141
202
|
|
|
@@ -166,11 +227,11 @@ async function validateExecutionPayloadBid(
|
|
|
166
227
|
// [IGNORE] this bid is the highest value bid seen for the tuple
|
|
167
228
|
// `(bid.slot, bid.parent_block_hash, bid.parent_block_root)`.
|
|
168
229
|
const bestBid = chain.executionPayloadBidPool.getBestBid(bid.slot, parentBlockHashHex, parentBlockRootHex);
|
|
169
|
-
if (bestBid !== null && bestBid.value >= bid.value) {
|
|
230
|
+
if (bestBid !== null && bestBid.message.value >= bid.value) {
|
|
170
231
|
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
171
232
|
code: ExecutionPayloadBidErrorCode.BID_TOO_LOW,
|
|
172
233
|
bidValue: bid.value,
|
|
173
|
-
currentHighestBid: bestBid.value,
|
|
234
|
+
currentHighestBid: bestBid.message.value,
|
|
174
235
|
});
|
|
175
236
|
}
|
|
176
237
|
// [IGNORE] `bid.value` is less or equal than the builder's excess balance --
|
|
@@ -183,9 +244,17 @@ async function validateExecutionPayloadBid(
|
|
|
183
244
|
});
|
|
184
245
|
}
|
|
185
246
|
|
|
186
|
-
// [
|
|
187
|
-
//
|
|
188
|
-
|
|
247
|
+
// [REJECT] `bid.prev_randao` is the correct RANDAO mix -- i.e. validate that
|
|
248
|
+
// `bid.prev_randao == get_randao_mix(parent_state, get_current_epoch(parent_state))`.
|
|
249
|
+
const randaoMix = state.getRandaoMix(computeEpochAtSlot(state.slot));
|
|
250
|
+
if (!byteArrayEquals(bid.prevRandao, randaoMix)) {
|
|
251
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
252
|
+
code: ExecutionPayloadBidErrorCode.INVALID_PREV_RANDAO,
|
|
253
|
+
builderIndex: bid.builderIndex,
|
|
254
|
+
bidPrevRandao: toHex(bid.prevRandao),
|
|
255
|
+
expectedPrevRandao: toHex(randaoMix),
|
|
256
|
+
});
|
|
257
|
+
}
|
|
189
258
|
|
|
190
259
|
// [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
|
|
191
260
|
const signatureSet = createSingleSignatureSetFromComponents(
|
|
@@ -204,4 +273,6 @@ async function validateExecutionPayloadBid(
|
|
|
204
273
|
|
|
205
274
|
// Valid
|
|
206
275
|
chain.seenExecutionPayloadBids.add(bid.slot, bid.builderIndex);
|
|
276
|
+
|
|
277
|
+
return {proposerIndex: proposerPreferences.message.validatorIndex};
|
|
207
278
|
}
|
|
@@ -35,8 +35,6 @@ async function validateExecutionPayloadEnvelope(
|
|
|
35
35
|
// [IGNORE] The envelope's block root `envelope.beacon_block_root` has been seen (via
|
|
36
36
|
// gossip or non-gossip sources) (a client MAY queue payload for processing once
|
|
37
37
|
// the block is retrieved).
|
|
38
|
-
// TODO GLOAS: Need to review this, we should queue the envelope for later
|
|
39
|
-
// processing if the block is not yet known, otherwise we would ignore it here
|
|
40
38
|
const block = chain.forkChoice.getBlockDefaultStatus(envelope.beaconBlockRoot);
|
|
41
39
|
if (block === null) {
|
|
42
40
|
throw new ExecutionPayloadEnvelopeError(GossipAction.IGNORE, {
|
|
@@ -108,7 +106,7 @@ async function validateExecutionPayloadEnvelope(
|
|
|
108
106
|
}
|
|
109
107
|
|
|
110
108
|
// [REJECT] `hash_tree_root(envelope.execution_requests) == bid.execution_requests_root`
|
|
111
|
-
const requestsRoot = ssz.
|
|
109
|
+
const requestsRoot = ssz.gloas.ExecutionRequests.hashTreeRoot(envelope.executionRequests);
|
|
112
110
|
if (!byteArrayEquals(requestsRoot, payloadInput.getBid().executionRequestsRoot)) {
|
|
113
111
|
throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
|
|
114
112
|
code: ExecutionPayloadEnvelopeErrorCode.EXECUTION_REQUESTS_ROOT_MISMATCH,
|
|
@@ -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
|
|
|
@@ -244,7 +244,7 @@ export class ExecutionEngineHttp implements IExecutionEngine {
|
|
|
244
244
|
if (executionRequests === undefined) {
|
|
245
245
|
throw Error(`executionRequests required in notifyNewPayload for fork=${fork}`);
|
|
246
246
|
}
|
|
247
|
-
const serializedExecutionRequests = serializeExecutionRequests(executionRequests);
|
|
247
|
+
const serializedExecutionRequests = serializeExecutionRequests(fork, executionRequests);
|
|
248
248
|
engineRequest = {
|
|
249
249
|
method: ForkSeq[fork] >= ForkSeq.gloas ? "engine_newPayloadV5" : "engine_newPayloadV4",
|
|
250
250
|
params: [
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {routes} from "@lodestar/api";
|
|
2
2
|
import {
|
|
3
|
+
BUILDER_DEPOSIT_REQUEST_TYPE,
|
|
4
|
+
BUILDER_EXIT_REQUEST_TYPE,
|
|
3
5
|
CONSOLIDATION_REQUEST_TYPE,
|
|
4
6
|
DEPOSIT_REQUEST_TYPE,
|
|
5
7
|
ForkName,
|
|
@@ -51,10 +53,18 @@ export enum ExecutionEngineState {
|
|
|
51
53
|
export type ExecutionRequestType =
|
|
52
54
|
| typeof DEPOSIT_REQUEST_TYPE
|
|
53
55
|
| typeof WITHDRAWAL_REQUEST_TYPE
|
|
54
|
-
| typeof CONSOLIDATION_REQUEST_TYPE
|
|
56
|
+
| typeof CONSOLIDATION_REQUEST_TYPE
|
|
57
|
+
| typeof BUILDER_DEPOSIT_REQUEST_TYPE
|
|
58
|
+
| typeof BUILDER_EXIT_REQUEST_TYPE;
|
|
55
59
|
|
|
56
60
|
export function isExecutionRequestType(type: number): type is ExecutionRequestType {
|
|
57
|
-
return
|
|
61
|
+
return (
|
|
62
|
+
type === DEPOSIT_REQUEST_TYPE ||
|
|
63
|
+
type === WITHDRAWAL_REQUEST_TYPE ||
|
|
64
|
+
type === CONSOLIDATION_REQUEST_TYPE ||
|
|
65
|
+
type === BUILDER_DEPOSIT_REQUEST_TYPE ||
|
|
66
|
+
type === BUILDER_EXIT_REQUEST_TYPE
|
|
67
|
+
);
|
|
58
68
|
}
|
|
59
69
|
|
|
60
70
|
export type ExecutePayloadResponse =
|
|
@@ -393,11 +393,12 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
|
|
|
393
393
|
blobs,
|
|
394
394
|
proofs,
|
|
395
395
|
}),
|
|
396
|
-
executionRequests: serializeExecutionRequests(
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
396
|
+
executionRequests: serializeExecutionRequests(
|
|
397
|
+
fork,
|
|
398
|
+
ForkSeq[fork] >= ForkSeq.gloas
|
|
399
|
+
? ssz.gloas.ExecutionRequests.defaultValue()
|
|
400
|
+
: ssz.electra.ExecutionRequests.defaultValue()
|
|
401
|
+
),
|
|
401
402
|
});
|
|
402
403
|
|
|
403
404
|
// IF the payload is deemed VALID and the build process has begun
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
|
+
BUILDER_DEPOSIT_REQUEST_TYPE,
|
|
3
|
+
BUILDER_EXIT_REQUEST_TYPE,
|
|
2
4
|
BYTES_PER_FIELD_ELEMENT,
|
|
3
5
|
BYTES_PER_LOGS_BLOOM,
|
|
4
6
|
CELLS_PER_EXT_BLOB,
|
|
@@ -205,16 +207,27 @@ export type WithdrawalRpc = {
|
|
|
205
207
|
};
|
|
206
208
|
|
|
207
209
|
/**
|
|
208
|
-
* ExecutionRequestsRpc
|
|
209
|
-
* -
|
|
210
|
-
* - ssz'ed
|
|
211
|
-
* - ssz'ed
|
|
210
|
+
* ExecutionRequestsRpc holds at most 5 elements and no repeated type, ordered by
|
|
211
|
+
* the single-byte request type prefix:
|
|
212
|
+
* - ssz'ed DepositRequests (0x00)
|
|
213
|
+
* - ssz'ed WithdrawalRequests (0x01)
|
|
214
|
+
* - ssz'ed ConsolidationRequests (0x02)
|
|
215
|
+
* - ssz'ed BuilderDepositRequests (0x03)
|
|
216
|
+
* - ssz'ed BuilderExitRequests (0x04)
|
|
212
217
|
*/
|
|
213
|
-
export type ExecutionRequestsRpc = (
|
|
218
|
+
export type ExecutionRequestsRpc = (
|
|
219
|
+
| DepositRequestsRpc
|
|
220
|
+
| WithdrawalRequestsRpc
|
|
221
|
+
| ConsolidationRequestsRpc
|
|
222
|
+
| BuilderDepositRequestsRpc
|
|
223
|
+
| BuilderExitRequestsRpc
|
|
224
|
+
)[];
|
|
214
225
|
|
|
215
226
|
export type DepositRequestsRpc = DATA;
|
|
216
227
|
export type WithdrawalRequestsRpc = DATA;
|
|
217
228
|
export type ConsolidationRequestsRpc = DATA;
|
|
229
|
+
export type BuilderDepositRequestsRpc = DATA;
|
|
230
|
+
export type BuilderExitRequestsRpc = DATA;
|
|
218
231
|
|
|
219
232
|
export type BlobAndProofRpc = {
|
|
220
233
|
blob: DATA;
|
|
@@ -339,7 +352,7 @@ export function parseExecutionPayload(
|
|
|
339
352
|
data = response.executionPayload;
|
|
340
353
|
blobsBundle = response.blobsBundle ? parseBlobsBundle(response.blobsBundle) : undefined;
|
|
341
354
|
executionRequests = response.executionRequests
|
|
342
|
-
? deserializeExecutionRequests(response.executionRequests)
|
|
355
|
+
? deserializeExecutionRequests(fork, response.executionRequests)
|
|
343
356
|
: undefined;
|
|
344
357
|
shouldOverrideBuilder = response.shouldOverrideBuilder ?? false;
|
|
345
358
|
} else {
|
|
@@ -526,13 +539,36 @@ function deserializeConsolidationRequests(serialized: ConsolidationRequestsRpc):
|
|
|
526
539
|
return ssz.electra.ConsolidationRequests.deserialize(dataToBytes(serialized, null));
|
|
527
540
|
}
|
|
528
541
|
|
|
542
|
+
function serializeBuilderDepositRequests(
|
|
543
|
+
builderDepositRequests: gloas.BuilderDepositRequests
|
|
544
|
+
): BuilderDepositRequestsRpc {
|
|
545
|
+
const requestsBytes = ssz.gloas.BuilderDepositRequests.serialize(builderDepositRequests);
|
|
546
|
+
return bytesToData(prefixRequests(requestsBytes, BUILDER_DEPOSIT_REQUEST_TYPE));
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function deserializeBuilderDepositRequests(serialized: BuilderDepositRequestsRpc): gloas.BuilderDepositRequests {
|
|
550
|
+
return ssz.gloas.BuilderDepositRequests.deserialize(dataToBytes(serialized, null));
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
function serializeBuilderExitRequests(builderExitRequests: gloas.BuilderExitRequests): BuilderExitRequestsRpc {
|
|
554
|
+
const requestsBytes = ssz.gloas.BuilderExitRequests.serialize(builderExitRequests);
|
|
555
|
+
return bytesToData(prefixRequests(requestsBytes, BUILDER_EXIT_REQUEST_TYPE));
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function deserializeBuilderExitRequests(serialized: BuilderExitRequestsRpc): gloas.BuilderExitRequests {
|
|
559
|
+
return ssz.gloas.BuilderExitRequests.deserialize(dataToBytes(serialized, null));
|
|
560
|
+
}
|
|
561
|
+
|
|
529
562
|
/**
|
|
530
563
|
* This is identical to get_execution_requests_list in
|
|
531
564
|
* https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.8/specs/electra/beacon-chain.md#new-get_execution_requests_list
|
|
565
|
+
*
|
|
566
|
+
* Gloas extends the list with builder deposits (0x03) and builder exits (0x04) per
|
|
567
|
+
* https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.11/specs/gloas/beacon-chain.md#modified-get_execution_requests_list
|
|
532
568
|
*/
|
|
533
|
-
export function serializeExecutionRequests(executionRequests: ExecutionRequests): ExecutionRequestsRpc {
|
|
569
|
+
export function serializeExecutionRequests(fork: ForkName, executionRequests: ExecutionRequests): ExecutionRequestsRpc {
|
|
534
570
|
const {deposits, withdrawals, consolidations} = executionRequests;
|
|
535
|
-
const result = [];
|
|
571
|
+
const result: ExecutionRequestsRpc = [];
|
|
536
572
|
|
|
537
573
|
if (deposits.length !== 0) {
|
|
538
574
|
result.push(serializeDepositRequests(deposits));
|
|
@@ -546,15 +582,26 @@ export function serializeExecutionRequests(executionRequests: ExecutionRequests)
|
|
|
546
582
|
result.push(serializeConsolidationRequests(consolidations));
|
|
547
583
|
}
|
|
548
584
|
|
|
585
|
+
if (ForkSeq[fork] >= ForkSeq.gloas) {
|
|
586
|
+
const {builderDeposits, builderExits} = executionRequests as gloas.ExecutionRequests;
|
|
587
|
+
|
|
588
|
+
if (builderDeposits.length !== 0) {
|
|
589
|
+
result.push(serializeBuilderDepositRequests(builderDeposits));
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
if (builderExits.length !== 0) {
|
|
593
|
+
result.push(serializeBuilderExitRequests(builderExits));
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
549
597
|
return result;
|
|
550
598
|
}
|
|
551
599
|
|
|
552
|
-
export function deserializeExecutionRequests(serialized: ExecutionRequestsRpc): ExecutionRequests {
|
|
553
|
-
const result: ExecutionRequests =
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
};
|
|
600
|
+
export function deserializeExecutionRequests(fork: ForkName, serialized: ExecutionRequestsRpc): ExecutionRequests {
|
|
601
|
+
const result: ExecutionRequests =
|
|
602
|
+
ForkSeq[fork] >= ForkSeq.gloas
|
|
603
|
+
? {deposits: [], withdrawals: [], consolidations: [], builderDeposits: [], builderExits: []}
|
|
604
|
+
: {deposits: [], withdrawals: [], consolidations: []};
|
|
558
605
|
|
|
559
606
|
if (serialized.length === 0) {
|
|
560
607
|
return result;
|
|
@@ -601,6 +648,20 @@ export function deserializeExecutionRequests(serialized: ExecutionRequestsRpc):
|
|
|
601
648
|
result.consolidations = deserializeConsolidationRequests(requests);
|
|
602
649
|
break;
|
|
603
650
|
}
|
|
651
|
+
case BUILDER_DEPOSIT_REQUEST_TYPE: {
|
|
652
|
+
if (ForkSeq[fork] < ForkSeq.gloas) {
|
|
653
|
+
throw Error(`Builder deposit request is not supported pre-gloas fork=${fork}`);
|
|
654
|
+
}
|
|
655
|
+
(result as gloas.ExecutionRequests).builderDeposits = deserializeBuilderDepositRequests(requests);
|
|
656
|
+
break;
|
|
657
|
+
}
|
|
658
|
+
case BUILDER_EXIT_REQUEST_TYPE: {
|
|
659
|
+
if (ForkSeq[fork] < ForkSeq.gloas) {
|
|
660
|
+
throw Error(`Builder exit request is not supported pre-gloas fork=${fork}`);
|
|
661
|
+
}
|
|
662
|
+
(result as gloas.ExecutionRequests).builderExits = deserializeBuilderExitRequests(requests);
|
|
663
|
+
break;
|
|
664
|
+
}
|
|
604
665
|
}
|
|
605
666
|
prevRequestType = currentRequestType;
|
|
606
667
|
}
|
|
@@ -610,6 +610,11 @@ export function createLodestarMetrics(
|
|
|
610
610
|
help: "The origination source of one of the BlockInputSync triggers",
|
|
611
611
|
labelNames: ["source"],
|
|
612
612
|
}),
|
|
613
|
+
payloadSource: register.counter<{source: BlockInputSource}>({
|
|
614
|
+
name: "lodestar_payload_input_sync_source_total",
|
|
615
|
+
help: "Count of payload (execution payload envelope) sync triggers, labeled by their source",
|
|
616
|
+
labelNames: ["source"],
|
|
617
|
+
}),
|
|
613
618
|
pendingBlocks: register.gauge({
|
|
614
619
|
name: "lodestar_sync_unknown_block_pending_blocks_size",
|
|
615
620
|
help: "Current size of UnknownBlockSync pending blocks cache",
|
|
@@ -861,6 +866,12 @@ export function createLodestarMetrics(
|
|
|
861
866
|
labelNames: ["numBlobs"],
|
|
862
867
|
}),
|
|
863
868
|
|
|
869
|
+
skippedSlots: register.histogram({
|
|
870
|
+
name: "lodestar_gossip_block_skipped_slots",
|
|
871
|
+
help: "Number of skipped slots between a gossip block and its parent (blockSlot - parentSlot - 1)",
|
|
872
|
+
buckets: [0, 1, 2, 4, 8, 16, 32],
|
|
873
|
+
}),
|
|
874
|
+
|
|
864
875
|
processBlockErrors: register.gauge<{error: BlockErrorCode | "NOT_BLOCK_ERROR"}>({
|
|
865
876
|
name: "lodestar_gossip_block_process_block_errors",
|
|
866
877
|
help: "Count of errors, by error type, while processing blocks",
|
|
@@ -987,10 +998,11 @@ export function createLodestarMetrics(
|
|
|
987
998
|
}),
|
|
988
999
|
},
|
|
989
1000
|
importPayload: {
|
|
990
|
-
|
|
991
|
-
name: "
|
|
992
|
-
help: "
|
|
1001
|
+
elapsedTimeTillImported: register.histogram<{source: PayloadEnvelopeInputSource}>({
|
|
1002
|
+
name: "lodestar_import_payload_elapsed_time_till_imported_seconds",
|
|
1003
|
+
help: "Time elapsed between slot time and the time execution payload envelope is imported (added to fork choice)",
|
|
993
1004
|
labelNames: ["source"],
|
|
1005
|
+
buckets: [1, 2, 3, 6, 9, 12],
|
|
994
1006
|
}),
|
|
995
1007
|
columnsBySource: register.gauge<{source: PayloadEnvelopeInputSource}>({
|
|
996
1008
|
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);
|