@lodestar/beacon-node 1.43.0-dev.4358217e12 → 1.43.0-dev.4451fec75a
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 +10 -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 +45 -2
- 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 +0 -1
- 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 +68 -2
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.d.ts +3 -0
- package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
- package/lib/chain/blocks/blockInput/blockInput.js +4 -1
- package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
- package/lib/chain/blocks/importBlock.d.ts.map +1 -1
- package/lib/chain/blocks/importBlock.js +16 -31
- package/lib/chain/blocks/importBlock.js.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts +6 -1
- package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
- package/lib/chain/blocks/importExecutionPayload.js +19 -10
- package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
- package/lib/chain/blocks/index.d.ts.map +1 -1
- package/lib/chain/blocks/index.js +35 -21
- package/lib/chain/blocks/index.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +12 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +28 -2
- package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +17 -0
- package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
- package/lib/chain/blocks/types.d.ts +2 -1
- package/lib/chain/blocks/types.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.d.ts +1 -3
- package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
- package/lib/chain/blocks/utils/chainSegment.js +34 -23
- package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
- package/lib/chain/blocks/verifyBlock.d.ts +2 -1
- package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlock.js +30 -12
- package/lib/chain/blocks/verifyBlock.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +0 -4
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +5 -2
- package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts +2 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
- package/lib/chain/blocks/verifyBlocksSanityChecks.js +16 -7
- package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +10 -6
- package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
- package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js +8 -3
- package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +25 -8
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/emitter.d.ts +0 -11
- package/lib/chain/emitter.d.ts.map +1 -1
- package/lib/chain/emitter.js +0 -4
- package/lib/chain/emitter.js.map +1 -1
- package/lib/chain/errors/proposerPreferences.d.ts +8 -1
- package/lib/chain/errors/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/errors/proposerPreferences.js +1 -0
- package/lib/chain/errors/proposerPreferences.js.map +1 -1
- package/lib/chain/initState.d.ts.map +1 -1
- package/lib/chain/initState.js +6 -1
- package/lib/chain/initState.js.map +1 -1
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +1 -1
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.d.ts +2 -1
- package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.js +52 -10
- package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
- package/lib/chain/prepareNextSlot.d.ts.map +1 -1
- package/lib/chain/prepareNextSlot.js +16 -18
- package/lib/chain/prepareNextSlot.js.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.d.ts +12 -3
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +33 -20
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/regen/queued.d.ts.map +1 -1
- package/lib/chain/regen/queued.js +1 -4
- package/lib/chain/regen/queued.js.map +1 -1
- package/lib/chain/regen/regen.d.ts.map +1 -1
- package/lib/chain/regen/regen.js +1 -4
- package/lib/chain/regen/regen.js.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +21 -11
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +70 -20
- package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
- package/lib/chain/seenCache/seenProposerPreferences.d.ts +8 -7
- package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -1
- package/lib/chain/seenCache/seenProposerPreferences.js +11 -10
- package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +11 -8
- package/lib/chain/validation/executionPayloadBid.js.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts +1 -1
- package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
- package/lib/chain/validation/payloadAttestationMessage.js +5 -3
- package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
- package/lib/chain/validation/proposerPreferences.d.ts.map +1 -1
- package/lib/chain/validation/proposerPreferences.js +39 -17
- package/lib/chain/validation/proposerPreferences.js.map +1 -1
- package/lib/metrics/metrics/lodestar.d.ts +4 -0
- package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
- package/lib/metrics/metrics/lodestar.js +5 -0
- package/lib/metrics/metrics/lodestar.js.map +1 -1
- package/lib/network/gossip/topic.d.ts +751 -2
- package/lib/network/gossip/topic.d.ts.map +1 -1
- package/lib/network/interface.d.ts +2 -0
- package/lib/network/interface.d.ts.map +1 -1
- package/lib/network/network.d.ts +2 -0
- package/lib/network/network.d.ts.map +1 -1
- package/lib/network/network.js +8 -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 +61 -13
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/network/processor/index.js +5 -5
- package/lib/network/processor/index.js.map +1 -1
- package/lib/network/reqresp/ReqRespBeaconNode.d.ts.map +1 -1
- package/lib/network/reqresp/ReqRespBeaconNode.js +1 -1
- package/lib/network/reqresp/ReqRespBeaconNode.js.map +1 -1
- package/lib/network/reqresp/handlers/beaconBlocksByHead.d.ts +9 -0
- package/lib/network/reqresp/handlers/beaconBlocksByHead.d.ts.map +1 -0
- package/lib/network/reqresp/handlers/beaconBlocksByHead.js +61 -0
- package/lib/network/reqresp/handlers/beaconBlocksByHead.js.map +1 -0
- package/lib/network/reqresp/handlers/index.d.ts.map +1 -1
- package/lib/network/reqresp/handlers/index.js +5 -0
- package/lib/network/reqresp/handlers/index.js.map +1 -1
- package/lib/network/reqresp/interface.d.ts +1 -1
- package/lib/network/reqresp/interface.js +1 -1
- package/lib/network/reqresp/protocols.d.ts +1 -0
- package/lib/network/reqresp/protocols.d.ts.map +1 -1
- package/lib/network/reqresp/protocols.js +5 -0
- package/lib/network/reqresp/protocols.js.map +1 -1
- package/lib/network/reqresp/rateLimit.d.ts.map +1 -1
- package/lib/network/reqresp/rateLimit.js +4 -0
- package/lib/network/reqresp/rateLimit.js.map +1 -1
- package/lib/network/reqresp/score.d.ts.map +1 -1
- package/lib/network/reqresp/score.js +1 -0
- package/lib/network/reqresp/score.js.map +1 -1
- package/lib/network/reqresp/types.d.ts +3 -0
- package/lib/network/reqresp/types.d.ts.map +1 -1
- package/lib/network/reqresp/types.js +3 -0
- package/lib/network/reqresp/types.js.map +1 -1
- package/lib/node/nodejs.js +2 -2
- package/lib/node/nodejs.js.map +1 -1
- package/lib/node/notifier.js +1 -7
- package/lib/node/notifier.js.map +1 -1
- package/lib/sync/constants.d.ts +7 -1
- package/lib/sync/constants.d.ts.map +1 -1
- package/lib/sync/constants.js +7 -4
- package/lib/sync/constants.js.map +1 -1
- package/lib/sync/range/batch.d.ts +43 -6
- package/lib/sync/range/batch.d.ts.map +1 -1
- package/lib/sync/range/batch.js +243 -44
- package/lib/sync/range/batch.js.map +1 -1
- package/lib/sync/range/chain.d.ts +16 -2
- package/lib/sync/range/chain.d.ts.map +1 -1
- package/lib/sync/range/chain.js +100 -9
- package/lib/sync/range/chain.js.map +1 -1
- package/lib/sync/range/range.d.ts.map +1 -1
- package/lib/sync/range/range.js +54 -5
- package/lib/sync/range/range.js.map +1 -1
- package/lib/sync/range/utils/peerBalancer.d.ts +2 -1
- package/lib/sync/range/utils/peerBalancer.d.ts.map +1 -1
- package/lib/sync/range/utils/peerBalancer.js +8 -4
- package/lib/sync/range/utils/peerBalancer.js.map +1 -1
- package/lib/sync/sync.d.ts.map +1 -1
- package/lib/sync/sync.js +13 -0
- package/lib/sync/sync.js.map +1 -1
- package/lib/sync/unknownBlock.d.ts +7 -2
- package/lib/sync/unknownBlock.d.ts.map +1 -1
- package/lib/sync/unknownBlock.js +127 -57
- package/lib/sync/unknownBlock.js.map +1 -1
- package/lib/sync/utils/downloadByRange.d.ts +36 -9
- package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRange.js +106 -42
- package/lib/sync/utils/downloadByRange.js.map +1 -1
- package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
- package/lib/sync/utils/downloadByRoot.js +10 -0
- package/lib/sync/utils/downloadByRoot.js.map +1 -1
- package/lib/sync/utils/rateLimit.d.ts +2 -0
- package/lib/sync/utils/rateLimit.d.ts.map +1 -0
- package/lib/sync/utils/rateLimit.js +15 -0
- package/lib/sync/utils/rateLimit.js.map +1 -0
- package/lib/util/sszBytes.d.ts.map +1 -1
- package/lib/util/sszBytes.js +8 -6
- package/lib/util/sszBytes.js.map +1 -1
- package/package.json +15 -16
- package/src/api/impl/beacon/blocks/index.ts +13 -0
- package/src/api/impl/beacon/pool/index.ts +83 -1
- package/src/api/impl/debug/index.ts +0 -1
- package/src/api/impl/validator/index.ts +82 -1
- package/src/chain/blocks/blockInput/blockInput.ts +4 -1
- package/src/chain/blocks/importBlock.ts +16 -50
- package/src/chain/blocks/importExecutionPayload.ts +32 -15
- package/src/chain/blocks/index.ts +32 -15
- package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +37 -3
- package/src/chain/blocks/payloadEnvelopeInput/types.ts +18 -0
- package/src/chain/blocks/types.ts +2 -1
- package/src/chain/blocks/utils/chainSegment.ts +35 -24
- package/src/chain/blocks/verifyBlock.ts +45 -13
- package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
- package/src/chain/blocks/verifyBlocksSanityChecks.ts +16 -6
- package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +14 -6
- package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
- package/src/chain/chain.ts +29 -7
- package/src/chain/emitter.ts +0 -11
- package/src/chain/errors/proposerPreferences.ts +9 -1
- package/src/chain/initState.ts +9 -1
- package/src/chain/lightClient/index.ts +6 -6
- package/src/chain/opPools/payloadAttestationPool.ts +59 -10
- package/src/chain/prepareNextSlot.ts +21 -29
- package/src/chain/produceBlock/produceBlockBody.ts +41 -25
- package/src/chain/regen/queued.ts +2 -7
- package/src/chain/regen/regen.ts +2 -7
- package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +90 -24
- package/src/chain/seenCache/seenProposerPreferences.ts +14 -11
- package/src/chain/validation/executionPayloadBid.ts +11 -8
- package/src/chain/validation/payloadAttestationMessage.ts +6 -4
- package/src/chain/validation/proposerPreferences.ts +37 -18
- package/src/metrics/metrics/lodestar.ts +6 -0
- package/src/network/interface.ts +2 -0
- package/src/network/network.ts +23 -0
- package/src/network/processor/gossipHandlers.ts +75 -14
- package/src/network/processor/index.ts +5 -5
- package/src/network/reqresp/ReqRespBeaconNode.ts +1 -0
- package/src/network/reqresp/handlers/beaconBlocksByHead.ts +91 -0
- package/src/network/reqresp/handlers/index.ts +5 -0
- package/src/network/reqresp/interface.ts +1 -1
- package/src/network/reqresp/protocols.ts +6 -0
- package/src/network/reqresp/rateLimit.ts +4 -0
- package/src/network/reqresp/score.ts +1 -0
- package/src/network/reqresp/types.ts +5 -0
- package/src/node/nodejs.ts +2 -2
- package/src/node/notifier.ts +1 -8
- package/src/sync/constants.ts +8 -4
- package/src/sync/range/batch.ts +309 -51
- package/src/sync/range/chain.ts +119 -10
- package/src/sync/range/range.ts +68 -5
- package/src/sync/range/utils/peerBalancer.ts +9 -3
- package/src/sync/sync.ts +13 -1
- package/src/sync/unknownBlock.ts +157 -60
- package/src/sync/utils/downloadByRange.ts +174 -44
- package/src/sync/utils/downloadByRoot.ts +12 -0
- package/src/sync/utils/rateLimit.ts +16 -0
- package/src/util/sszBytes.ts +8 -6
|
@@ -65,7 +65,7 @@ export async function processBlocks(
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
try {
|
|
68
|
-
const {relevantBlocks, parentSlots, parentBlock} = verifyBlocksSanityChecks(this, blocks, opts);
|
|
68
|
+
const {relevantBlocks, parentSlots, parentBlock} = verifyBlocksSanityChecks(this, blocks, payloadEnvelopes, opts);
|
|
69
69
|
|
|
70
70
|
// No relevant blocks, skip verifyBlocksInEpoch()
|
|
71
71
|
if (relevantBlocks.length === 0 || parentBlock === null) {
|
|
@@ -90,8 +90,14 @@ export async function processBlocks(
|
|
|
90
90
|
|
|
91
91
|
// Fully verify a block to be imported immediately after. Does not produce any side-effects besides adding intermediate
|
|
92
92
|
// states in the state cache through regen.
|
|
93
|
-
const {
|
|
94
|
-
|
|
93
|
+
const {
|
|
94
|
+
postStates,
|
|
95
|
+
blockDAStatuses,
|
|
96
|
+
payloadDAStatuses,
|
|
97
|
+
proposerBalanceDeltas,
|
|
98
|
+
segmentExecStatus,
|
|
99
|
+
indexedAttestationsByBlock,
|
|
100
|
+
} = await verifyBlocksInEpoch.call(this, parentBlock, relevantBlocks, payloadEnvelopes, opts);
|
|
95
101
|
|
|
96
102
|
// If segmentExecStatus has lvhForkchoice then, the entire segment should be invalid
|
|
97
103
|
// and we need to further propagate
|
|
@@ -103,26 +109,35 @@ export async function processBlocks(
|
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
const {executionStatuses} = segmentExecStatus;
|
|
106
|
-
const
|
|
107
|
-
|
|
112
|
+
const verifiedBlocksBySlot = new Map<Slot, FullyVerifiedBlock>();
|
|
113
|
+
for (let i = 0; i < relevantBlocks.length; i++) {
|
|
114
|
+
const block = relevantBlocks[i];
|
|
115
|
+
verifiedBlocksBySlot.set(block.getBlock().message.slot, {
|
|
108
116
|
blockInput: block,
|
|
109
117
|
postState: postStates[i],
|
|
110
118
|
parentBlockSlot: parentSlots[i],
|
|
111
119
|
executionStatus: executionStatuses[i],
|
|
112
120
|
// start supporting optimistic syncing/processing
|
|
113
|
-
dataAvailabilityStatus:
|
|
121
|
+
dataAvailabilityStatus: blockDAStatuses[i],
|
|
114
122
|
proposerBalanceDelta: proposerBalanceDeltas[i],
|
|
115
123
|
indexedAttestations: indexedAttestationsByBlock[i],
|
|
116
124
|
// TODO: Make this param mandatory and capture in gossip
|
|
117
125
|
seenTimestampSec: opts.seenTimestampSec ?? Math.floor(Date.now() / 1000),
|
|
118
|
-
})
|
|
119
|
-
|
|
126
|
+
});
|
|
127
|
+
}
|
|
120
128
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
129
|
+
const slotSet = new Set<Slot>(blocks.map((b) => b.getBlock().message.slot));
|
|
130
|
+
if (payloadEnvelopes) {
|
|
131
|
+
for (const slot of payloadEnvelopes.keys()) slotSet.add(slot);
|
|
132
|
+
}
|
|
133
|
+
const slots = Array.from(slotSet).sort((a, b) => a - b);
|
|
134
|
+
for (const slot of slots) {
|
|
135
|
+
const fullyVerifiedBlock = verifiedBlocksBySlot.get(slot);
|
|
136
|
+
if (fullyVerifiedBlock !== undefined) {
|
|
137
|
+
// TODO: Consider batching importBlock too if it takes significant time
|
|
138
|
+
await importBlock.call(this, fullyVerifiedBlock, opts);
|
|
139
|
+
}
|
|
124
140
|
|
|
125
|
-
const slot = fullyVerifiedBlock.blockInput.getBlock().message.slot;
|
|
126
141
|
const payloadInput = payloadEnvelopes?.get(slot);
|
|
127
142
|
if (payloadInput?.hasPayloadEnvelope()) {
|
|
128
143
|
if (!payloadInput.isComplete()) {
|
|
@@ -130,9 +145,11 @@ export async function processBlocks(
|
|
|
130
145
|
throw new Error(`Payload envelope for slot ${slot} not complete after DA verification`);
|
|
131
146
|
}
|
|
132
147
|
// we already awaited DA in verifyBlocksInEpoch for this segment
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
148
|
+
const payloadDA = payloadDAStatuses.get(slot);
|
|
149
|
+
if (payloadDA === undefined) {
|
|
150
|
+
throw new Error(`Missing payload DA status for slot ${slot}`);
|
|
151
|
+
}
|
|
152
|
+
await importExecutionPayload.call(this, payloadInput, payloadDA, {validSignature: false});
|
|
136
153
|
}
|
|
137
154
|
|
|
138
155
|
await nextEventLoop();
|
|
@@ -4,7 +4,13 @@ import {toRootHex, withTimeout} from "@lodestar/utils";
|
|
|
4
4
|
import {VersionedHashes} from "../../../execution/index.js";
|
|
5
5
|
import {kzgCommitmentToVersionedHash} from "../../../util/blobs.js";
|
|
6
6
|
import {MissingColumnMeta} from "../blockInput/types.js";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
AddPayloadEnvelopeProps,
|
|
9
|
+
ColumnWithSource,
|
|
10
|
+
CreateFromBidProps,
|
|
11
|
+
CreateFromBlockProps,
|
|
12
|
+
SourceMeta,
|
|
13
|
+
} from "./types.js";
|
|
8
14
|
|
|
9
15
|
export type PayloadEnvelopeInputState =
|
|
10
16
|
| {
|
|
@@ -64,6 +70,7 @@ export class PayloadEnvelopeInput {
|
|
|
64
70
|
readonly proposerIndex: ValidatorIndex;
|
|
65
71
|
readonly bid: gloas.ExecutionPayloadBid;
|
|
66
72
|
readonly versionedHashes: VersionedHashes;
|
|
73
|
+
readonly daOutOfRange: boolean;
|
|
67
74
|
|
|
68
75
|
private columnsCache = new Map<ColumnIndex, ColumnWithSource>();
|
|
69
76
|
|
|
@@ -87,6 +94,7 @@ export class PayloadEnvelopeInput {
|
|
|
87
94
|
sampledColumns: ColumnIndex[];
|
|
88
95
|
custodyColumns: ColumnIndex[];
|
|
89
96
|
timeCreatedSec: number;
|
|
97
|
+
daOutOfRange: boolean;
|
|
90
98
|
}) {
|
|
91
99
|
this.blockRootHex = props.blockRootHex;
|
|
92
100
|
this.slot = props.slot;
|
|
@@ -97,13 +105,14 @@ export class PayloadEnvelopeInput {
|
|
|
97
105
|
this.sampledColumns = props.sampledColumns;
|
|
98
106
|
this.custodyColumns = props.custodyColumns;
|
|
99
107
|
this.timeCreatedSec = props.timeCreatedSec;
|
|
108
|
+
this.daOutOfRange = props.daOutOfRange;
|
|
100
109
|
this.payloadEnvelopeDataPromise = createPromise();
|
|
101
110
|
this.allDataPromise = createPromise();
|
|
102
111
|
this.columnsDataPromise = createPromise();
|
|
103
112
|
|
|
104
113
|
const noBlobs = props.bid.blobKzgCommitments.length === 0;
|
|
105
114
|
const noSampledColumns = props.sampledColumns.length === 0;
|
|
106
|
-
const hasAllData = noBlobs || noSampledColumns;
|
|
115
|
+
const hasAllData = props.daOutOfRange || noBlobs || noSampledColumns;
|
|
107
116
|
|
|
108
117
|
if (hasAllData) {
|
|
109
118
|
this.state = {hasPayload: false, hasAllData: true, hasComputedAllData: true};
|
|
@@ -125,6 +134,27 @@ export class PayloadEnvelopeInput {
|
|
|
125
134
|
sampledColumns: props.sampledColumns,
|
|
126
135
|
custodyColumns: props.custodyColumns,
|
|
127
136
|
timeCreatedSec: props.timeCreatedSec,
|
|
137
|
+
daOutOfRange: props.daOutOfRange,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Create a `PayloadEnvelopeInput` from a state's `latestExecutionPayloadBid` (the bid
|
|
143
|
+
* recorded in beacon state for the latest imported block). Used when seeding the cache
|
|
144
|
+
* for a checkpoint anchor block — we have the bid via state but not the full
|
|
145
|
+
* SignedBeaconBlock body.
|
|
146
|
+
*/
|
|
147
|
+
static createFromBid(props: CreateFromBidProps): PayloadEnvelopeInput {
|
|
148
|
+
return new PayloadEnvelopeInput({
|
|
149
|
+
blockRootHex: props.blockRootHex,
|
|
150
|
+
slot: props.slot,
|
|
151
|
+
forkName: props.forkName,
|
|
152
|
+
proposerIndex: props.proposerIndex,
|
|
153
|
+
bid: props.bid,
|
|
154
|
+
sampledColumns: props.sampledColumns,
|
|
155
|
+
custodyColumns: props.custodyColumns,
|
|
156
|
+
timeCreatedSec: props.timeCreatedSec,
|
|
157
|
+
daOutOfRange: props.daOutOfRange,
|
|
128
158
|
});
|
|
129
159
|
}
|
|
130
160
|
|
|
@@ -152,6 +182,7 @@ export class PayloadEnvelopeInput {
|
|
|
152
182
|
throw new Error("Payload envelope beacon_block_root mismatch");
|
|
153
183
|
}
|
|
154
184
|
|
|
185
|
+
// TODO GLOAS: track source by metrics, maybe inside the seen cache
|
|
155
186
|
const source: SourceMeta = {
|
|
156
187
|
source: props.source,
|
|
157
188
|
seenTimestampSec: props.seenTimestampSec,
|
|
@@ -306,8 +337,11 @@ export class PayloadEnvelopeInput {
|
|
|
306
337
|
return this.state.hasAllData;
|
|
307
338
|
}
|
|
308
339
|
|
|
340
|
+
/**
|
|
341
|
+
* Strictly checks missing sampled columns. Does NOT short-circuit on `state.hasAllData`.
|
|
342
|
+
*/
|
|
309
343
|
getMissingSampledColumnMeta(): MissingColumnMeta {
|
|
310
|
-
if (this.state.
|
|
344
|
+
if (this.state.hasComputedAllData) {
|
|
311
345
|
return {missing: [], versionedHashes: this.versionedHashes};
|
|
312
346
|
}
|
|
313
347
|
|
|
@@ -27,6 +27,24 @@ export type CreateFromBlockProps = {
|
|
|
27
27
|
sampledColumns: ColumnIndex[];
|
|
28
28
|
custodyColumns: ColumnIndex[];
|
|
29
29
|
timeCreatedSec: number;
|
|
30
|
+
daOutOfRange: boolean;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Used to seed an entry from a state's `latestExecutionPayloadBid` (e.g., when initializing
|
|
35
|
+
* the chain from a checkpoint anchor state — we have the bid via the state but not the
|
|
36
|
+
* full SignedBeaconBlock).
|
|
37
|
+
*/
|
|
38
|
+
export type CreateFromBidProps = {
|
|
39
|
+
blockRootHex: RootHex;
|
|
40
|
+
slot: number;
|
|
41
|
+
forkName: ForkName;
|
|
42
|
+
proposerIndex: number;
|
|
43
|
+
bid: gloas.ExecutionPayloadBid;
|
|
44
|
+
sampledColumns: ColumnIndex[];
|
|
45
|
+
custodyColumns: ColumnIndex[];
|
|
46
|
+
timeCreatedSec: number;
|
|
47
|
+
daOutOfRange: boolean;
|
|
30
48
|
};
|
|
31
49
|
|
|
32
50
|
export type AddPayloadEnvelopeProps = SourceMeta & {
|
|
@@ -94,7 +94,8 @@ export type ImportBlockOpts = {
|
|
|
94
94
|
*
|
|
95
95
|
* `executionStatus` reflects the outcome of execution payload verification at block-import time:
|
|
96
96
|
* - pre-gloas: Valid | Syncing | PreMerge (from EL notifyNewPayload against the in-block payload)
|
|
97
|
-
* - post-gloas:
|
|
97
|
+
* - post-gloas: inherited from parent's chain (Valid/Syncing) by importBlock; payload arrives
|
|
98
|
+
* separately as an envelope and creates the FULL variant later via onExecutionPayload
|
|
98
99
|
*/
|
|
99
100
|
export type FullyVerifiedBlock = {
|
|
100
101
|
blockInput: IBlockInput;
|
|
@@ -17,8 +17,6 @@ export type ChainSegmentResult = {warnings: OrphanedPayloadEnvelope[] | null};
|
|
|
17
17
|
* Assert this chain segment of blocks is linear with slot numbers and hashes,
|
|
18
18
|
* and that the provided envelopes are consistent with their respective blocks.
|
|
19
19
|
*
|
|
20
|
-
* Must be called after verifyBlocksSanityChecks so that parentBlock (from forkchoice)
|
|
21
|
-
* is available to seed the execution hash chain.
|
|
22
20
|
*
|
|
23
21
|
* For each block:
|
|
24
22
|
* - Verifies parent root + slot linearity
|
|
@@ -31,7 +29,7 @@ export function assertLinearChainSegment(
|
|
|
31
29
|
config: ChainForkConfig,
|
|
32
30
|
blocks: IBlockInput[],
|
|
33
31
|
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
34
|
-
parentBlock: ProtoBlock
|
|
32
|
+
parentBlock: ProtoBlock | null
|
|
35
33
|
): ChainSegmentResult {
|
|
36
34
|
const warnings: OrphanedPayloadEnvelope[] = [];
|
|
37
35
|
|
|
@@ -39,8 +37,17 @@ export function assertLinearChainSegment(
|
|
|
39
37
|
// Starts from the known forkchoice parent's execution hash.
|
|
40
38
|
// - FULL variant (envelope present for slot): advances to envelope.payload.blockHash
|
|
41
39
|
// - EMPTY variant (no envelope for slot): execution hash is unchanged
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
let currentExecHash: string | null = parentBlock?.executionPayloadBlockHash ?? null;
|
|
41
|
+
// Checkpoint sync first batch: parent is the anchor PENDING whose executionPayloadBlockHash
|
|
42
|
+
// is the inherited parentBlockHash semantic (= grandparent's payload), not its own payload.
|
|
43
|
+
// If parent's own payload envelope arrives in this batch, advance currentExecHash to that
|
|
44
|
+
// payload's blockHash so the segment validation sees the true EL chain head.
|
|
45
|
+
if (parentBlock !== null) {
|
|
46
|
+
const parentPayloadInput = payloadEnvelopes?.get(parentBlock.slot);
|
|
47
|
+
if (parentPayloadInput?.hasPayloadEnvelope()) {
|
|
48
|
+
currentExecHash = parentPayloadInput.getBlockHashHex();
|
|
49
|
+
}
|
|
50
|
+
}
|
|
44
51
|
// Track the execution hash before the last FULL advancement so we can recover
|
|
45
52
|
// if the next block reveals that envelope was orphaned.
|
|
46
53
|
let prevExecHash: string | null = currentExecHash;
|
|
@@ -68,27 +75,31 @@ export function assertLinearChainSegment(
|
|
|
68
75
|
}
|
|
69
76
|
}
|
|
70
77
|
|
|
71
|
-
if (isGloasBeaconBlock(block.message)
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
if (bidParentHash !==
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
78
|
+
if (isGloasBeaconBlock(block.message)) {
|
|
79
|
+
// Bid check fires only when we have a seeded execution hash. With parentBlock=null the
|
|
80
|
+
// chain is seeded mid-segment by the first FULL envelope.
|
|
81
|
+
if (currentExecHash !== null) {
|
|
82
|
+
// Verify the bid's parentBlockHash matches the tracked execution hash.
|
|
83
|
+
// This ensures the block was built on the correct FULL or EMPTY variant of its parent.
|
|
84
|
+
const bidParentHash = toRootHex(block.message.body.signedExecutionPayloadBid.message.parentBlockHash);
|
|
85
|
+
if (bidParentHash !== currentExecHash) {
|
|
86
|
+
// Maybe the previous slot's FULL envelope was orphaned — try falling back.
|
|
87
|
+
// If even prevExecHash doesn't match, the segment is non-linear.
|
|
88
|
+
if (bidParentHash !== prevExecHash) {
|
|
89
|
+
throw new BlockError(block, {
|
|
90
|
+
code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN,
|
|
91
|
+
parentRoot: toRootHex(block.message.parentRoot),
|
|
92
|
+
parentBlockHash: bidParentHash,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
if (lastFullSlot !== null && payloadEnvelopes !== null) {
|
|
96
|
+
const orphanedInput = payloadEnvelopes.get(lastFullSlot);
|
|
97
|
+
if (orphanedInput != null) {
|
|
98
|
+
warnings.push({slot: lastFullSlot, payloadEnvelopeInput: orphanedInput});
|
|
99
|
+
}
|
|
89
100
|
}
|
|
101
|
+
currentExecHash = prevExecHash;
|
|
90
102
|
}
|
|
91
|
-
currentExecHash = prevExecHash;
|
|
92
103
|
}
|
|
93
104
|
|
|
94
105
|
const payloadInput = payloadEnvelopes?.get(slot) ?? null;
|
|
@@ -41,7 +41,8 @@ export async function verifyBlocksInEpoch(
|
|
|
41
41
|
postStates: IBeaconStateView[];
|
|
42
42
|
proposerBalanceDeltas: number[];
|
|
43
43
|
segmentExecStatus: SegmentExecStatus;
|
|
44
|
-
|
|
44
|
+
blockDAStatuses: DataAvailabilityStatus[];
|
|
45
|
+
payloadDAStatuses: Map<Slot, DataAvailabilityStatus>;
|
|
45
46
|
indexedAttestationsByBlock: IndexedAttestation[][];
|
|
46
47
|
}> {
|
|
47
48
|
const blocks = blockInputs.map((blockInput) => blockInput.getBlock());
|
|
@@ -116,28 +117,52 @@ export async function verifyBlocksInEpoch(
|
|
|
116
117
|
|
|
117
118
|
// Pick the data-availability source by fork:
|
|
118
119
|
// - Pre-Gloas: blob/Fulu-column data lives in IBlockInput → verifyBlocksDataAvailability.
|
|
119
|
-
// - Post-Gloas: verifyPayloadsDataAvailability
|
|
120
|
-
const daAvailabilityPromise
|
|
120
|
+
// - Post-Gloas: verifyPayloadsDataAvailability (payload-level DA, keyed by slot).
|
|
121
|
+
const daAvailabilityPromise: Promise<{
|
|
122
|
+
blockDAStatuses: DataAvailabilityStatus[];
|
|
123
|
+
payloadDAStatuses: Map<Slot, DataAvailabilityStatus>;
|
|
124
|
+
availableTime: number;
|
|
125
|
+
}> =
|
|
121
126
|
fork >= ForkSeq.gloas
|
|
122
127
|
? (async () => {
|
|
123
|
-
|
|
124
|
-
for
|
|
125
|
-
|
|
126
|
-
|
|
128
|
+
// Validate DA for ALL payloads in the Map, not just those paired with blockInputs.
|
|
129
|
+
// A checkpoint-sync batch may include a payload for a slot whose block was filtered
|
|
130
|
+
// out of relevantBlocks (e.g., the anchor at the finalized slot); that payload still
|
|
131
|
+
// needs DA validation so it can be imported in processBlocks.
|
|
132
|
+
const payloadInputsForDa: PayloadEnvelopeInput[] =
|
|
133
|
+
payloadEnvelopes !== null ? Array.from(payloadEnvelopes.values()) : [];
|
|
134
|
+
const {dataAvailabilityStatuses, availableTime} = await verifyPayloadsDataAvailability(
|
|
135
|
+
payloadInputsForDa,
|
|
136
|
+
abortController.signal
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
const payloadDAStatuses = new Map<Slot, DataAvailabilityStatus>();
|
|
140
|
+
for (let i = 0; i < payloadInputsForDa.length; i++) {
|
|
141
|
+
payloadDAStatuses.set(payloadInputsForDa[i].slot, dataAvailabilityStatuses[i]);
|
|
127
142
|
}
|
|
128
|
-
await verifyPayloadsDataAvailability(payloadInputsForDa, abortController.signal);
|
|
129
143
|
return {
|
|
130
144
|
// post-gloas, DataAvailabilityStatus is NotRequired for forkChoice.onBlock() ProtoBlock
|
|
131
|
-
|
|
132
|
-
|
|
145
|
+
blockDAStatuses: blockInputs.map(() => DataAvailabilityStatus.NotRequired),
|
|
146
|
+
payloadDAStatuses,
|
|
147
|
+
availableTime,
|
|
133
148
|
};
|
|
134
149
|
})()
|
|
135
|
-
:
|
|
150
|
+
: (async () => {
|
|
151
|
+
const {dataAvailabilityStatuses, availableTime} = await verifyBlocksDataAvailability(
|
|
152
|
+
blockInputs,
|
|
153
|
+
abortController.signal
|
|
154
|
+
);
|
|
155
|
+
return {
|
|
156
|
+
blockDAStatuses: dataAvailabilityStatuses,
|
|
157
|
+
payloadDAStatuses: new Map<Slot, DataAvailabilityStatus>(),
|
|
158
|
+
availableTime,
|
|
159
|
+
};
|
|
160
|
+
})();
|
|
136
161
|
|
|
137
162
|
// batch all I/O operations to reduce overhead
|
|
138
163
|
const [
|
|
139
164
|
segmentExecStatus,
|
|
140
|
-
{
|
|
165
|
+
{blockDAStatuses, payloadDAStatuses, availableTime},
|
|
141
166
|
{postStates, proposerBalanceDeltas, verifyStateTime},
|
|
142
167
|
{verifySignaturesTime},
|
|
143
168
|
] = await Promise.all([
|
|
@@ -258,7 +283,14 @@ export async function verifyBlocksInEpoch(
|
|
|
258
283
|
);
|
|
259
284
|
}
|
|
260
285
|
|
|
261
|
-
return {
|
|
286
|
+
return {
|
|
287
|
+
postStates,
|
|
288
|
+
blockDAStatuses,
|
|
289
|
+
payloadDAStatuses,
|
|
290
|
+
proposerBalanceDeltas,
|
|
291
|
+
segmentExecStatus,
|
|
292
|
+
indexedAttestationsByBlock,
|
|
293
|
+
};
|
|
262
294
|
} finally {
|
|
263
295
|
abortController.abort();
|
|
264
296
|
}
|
|
@@ -46,8 +46,7 @@ type VerifyBlockExecutionResponse =
|
|
|
46
46
|
| VerifyExecutionErrorResponse
|
|
47
47
|
| {executionStatus: ExecutionStatus.Valid; lvhResponse: LVHValidResponse; execError: null}
|
|
48
48
|
| {executionStatus: ExecutionStatus.Syncing; lvhResponse?: LVHValidResponse; execError: null}
|
|
49
|
-
| {executionStatus: ExecutionStatus.PreMerge; lvhResponse: undefined; execError: null}
|
|
50
|
-
| {executionStatus: ExecutionStatus.PayloadSeparated; lvhResponse: undefined; execError: null};
|
|
49
|
+
| {executionStatus: ExecutionStatus.PreMerge; lvhResponse: undefined; execError: null};
|
|
51
50
|
|
|
52
51
|
/**
|
|
53
52
|
* Verifies 1 or more execution payloads from a linear sequence of blocks.
|
|
@@ -145,9 +144,10 @@ export async function verifyBlockExecutionPayload(
|
|
|
145
144
|
): Promise<VerifyBlockExecutionResponse> {
|
|
146
145
|
const block = blockInput.getBlock();
|
|
147
146
|
|
|
148
|
-
// Gloas block doesn't have execution payload. Return
|
|
147
|
+
// Gloas block doesn't have execution payload. Return Syncing as a placeholder; the actual
|
|
148
|
+
// status for gloas PENDING/EMPTY is derived from parent's chain in importBlock.
|
|
149
149
|
if (isBlockInputNoData(blockInput)) {
|
|
150
|
-
return {executionStatus: ExecutionStatus.
|
|
150
|
+
return {executionStatus: ExecutionStatus.Syncing, lvhResponse: undefined, execError: null};
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/** Not null if execution is enabled */
|
|
@@ -198,6 +198,7 @@ export async function verifyBlockExecutionPayload(
|
|
|
198
198
|
executionStatus,
|
|
199
199
|
latestValidExecHash: execResult.latestValidHash,
|
|
200
200
|
invalidateFromParentBlockRoot: blockInput.parentRootHex,
|
|
201
|
+
invalidateFromParentBlockHash: toRootHex(executionPayloadEnabled.parentHash),
|
|
201
202
|
};
|
|
202
203
|
const execError = new BlockError(block, {
|
|
203
204
|
code: BlockErrorCode.EXECUTION_ENGINE_ERROR,
|
|
@@ -281,6 +282,7 @@ function getSegmentErrorResponse(
|
|
|
281
282
|
executionStatus: ExecutionStatus.Invalid,
|
|
282
283
|
latestValidExecHash: lvhResponse.latestValidExecHash,
|
|
283
284
|
invalidateFromParentBlockRoot: parentBlock.blockRoot,
|
|
285
|
+
invalidateFromParentBlockHash: parentBlock.executionPayloadBlockHash,
|
|
284
286
|
};
|
|
285
287
|
}
|
|
286
288
|
}
|
|
@@ -7,6 +7,7 @@ import {IClock} from "../../util/clock.js";
|
|
|
7
7
|
import {BlockError, BlockErrorCode} from "../errors/index.js";
|
|
8
8
|
import {IChainOptions} from "../options.js";
|
|
9
9
|
import {IBlockInput} from "./blockInput/types.js";
|
|
10
|
+
import {PayloadEnvelopeInput} from "./payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
10
11
|
import {ImportBlockOpts} from "./types.js";
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -30,6 +31,7 @@ export function verifyBlocksSanityChecks(
|
|
|
30
31
|
blacklistedBlocks: Map<RootHex, Slot | null>;
|
|
31
32
|
},
|
|
32
33
|
blocks: IBlockInput[],
|
|
34
|
+
payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
|
|
33
35
|
opts: ImportBlockOpts
|
|
34
36
|
): {
|
|
35
37
|
relevantBlocks: IBlockInput[];
|
|
@@ -100,13 +102,21 @@ export function verifyBlocksSanityChecks(
|
|
|
100
102
|
const parentBlockHash = toRootHex(block.message.body.signedExecutionPayloadBid.message.parentBlockHash);
|
|
101
103
|
const parentBlockWithPayload = chain.forkChoice.getBlockHexAndBlockHash(parentRoot, parentBlockHash);
|
|
102
104
|
if (!parentBlockWithPayload) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
// Checkpoint sync: parent's FULL variant may not be in fork-choice yet because the
|
|
106
|
+
// anchor block is initialized with PENDING+EMPTY only. The parent's payload arrives
|
|
107
|
+
// in the same batch via payloadEnvelopes and will be imported by processBlocks. If
|
|
108
|
+
// a matching payload is in the Map, accept the parent as known.
|
|
109
|
+
const parentPayloadInput = payloadEnvelopes?.get(parentBlockDefaultStatus.slot);
|
|
110
|
+
if (parentPayloadInput?.getBlockHashHex() !== parentBlockHash) {
|
|
111
|
+
throw new BlockError(block, {
|
|
112
|
+
code: BlockErrorCode.PARENT_PAYLOAD_UNKNOWN,
|
|
113
|
+
parentRoot,
|
|
114
|
+
parentBlockHash,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
} else {
|
|
118
|
+
parentBlock = parentBlockWithPayload;
|
|
108
119
|
}
|
|
109
|
-
parentBlock = parentBlockWithPayload;
|
|
110
120
|
}
|
|
111
121
|
// Parent is known to the fork-choice
|
|
112
122
|
parentBlockSlot = parentBlock.slot;
|
|
@@ -20,7 +20,7 @@ export type VerifyExecutionPayloadEnvelopeOpts = {
|
|
|
20
20
|
* performed outside this function, see `verifyExecutionPayloadEnvelopeSignature` and
|
|
21
21
|
* `importExecutionPayload` which run both in parallel with this check.
|
|
22
22
|
*
|
|
23
|
-
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.
|
|
23
|
+
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.6/specs/gloas/fork-choice.md#new-verify_execution_payload_envelope
|
|
24
24
|
*/
|
|
25
25
|
export function verifyExecutionPayloadEnvelope(
|
|
26
26
|
config: BeaconConfig,
|
|
@@ -43,6 +43,11 @@ export function verifyExecutionPayloadEnvelope(
|
|
|
43
43
|
`Envelope's block is not the latest block header envelope=${toRootHex(envelope.beaconBlockRoot)} latestBlockHeader=${toRootHex(headerRoot)}`
|
|
44
44
|
);
|
|
45
45
|
}
|
|
46
|
+
if (!byteArrayEquals(envelope.parentBeaconBlockRoot, state.latestBlockHeader.parentRoot)) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Envelope's parent_beacon_block_root mismatch envelope=${toRootHex(envelope.parentBeaconBlockRoot)} state=${toRootHex(state.latestBlockHeader.parentRoot)}`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
46
51
|
|
|
47
52
|
// Verify consistency with the committed bid
|
|
48
53
|
const bid = state.latestExecutionPayloadBid;
|
|
@@ -77,16 +82,19 @@ export function verifyExecutionPayloadEnvelope(
|
|
|
77
82
|
}
|
|
78
83
|
}
|
|
79
84
|
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
85
|
+
// should not use state.slot, it does not work for skipped slot checkpoint sync
|
|
86
|
+
const blockSlot = state.latestBlockHeader.slot;
|
|
87
|
+
if (payload.slotNumber !== blockSlot) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Slot mismatch between payload and latest block header payload=${payload.slotNumber} latestBlockHeader=${blockSlot}`
|
|
90
|
+
);
|
|
83
91
|
}
|
|
84
92
|
if (!byteArrayEquals(payload.parentHash, state.latestBlockHash)) {
|
|
85
93
|
throw new Error(
|
|
86
94
|
`Parent hash mismatch between payload and state payload=${toRootHex(payload.parentHash)} state=${toRootHex(state.latestBlockHash)}`
|
|
87
95
|
);
|
|
88
96
|
}
|
|
89
|
-
const expectedTimestamp = computeTimeAtSlot(config,
|
|
97
|
+
const expectedTimestamp = computeTimeAtSlot(config, blockSlot, state.genesisTime);
|
|
90
98
|
if (payload.timestamp !== expectedTimestamp) {
|
|
91
99
|
throw new Error(
|
|
92
100
|
`Timestamp mismatch between payload and state payload=${payload.timestamp} state=${expectedTimestamp}`
|
|
@@ -108,7 +116,7 @@ export function verifyExecutionPayloadEnvelope(
|
|
|
108
116
|
/**
|
|
109
117
|
* Verify the BLS signature of an execution payload envelope.
|
|
110
118
|
*
|
|
111
|
-
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.
|
|
119
|
+
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.6/specs/gloas/fork-choice.md#new-verify_execution_payload_envelope_signature
|
|
112
120
|
*/
|
|
113
121
|
export async function verifyExecutionPayloadEnvelopeSignature(
|
|
114
122
|
config: BeaconConfig,
|
|
@@ -28,11 +28,14 @@ export async function verifyPayloadsDataAvailability(
|
|
|
28
28
|
await Promise.all(promises);
|
|
29
29
|
|
|
30
30
|
const availableTime = Math.max(0, Math.max(...payloadInputs.map((payloadInput) => payloadInput.getTimeComplete())));
|
|
31
|
-
const dataAvailabilityStatuses: DataAvailabilityStatus[] = payloadInputs.map((payloadInput) =>
|
|
32
|
-
payloadInput.
|
|
31
|
+
const dataAvailabilityStatuses: DataAvailabilityStatus[] = payloadInputs.map((payloadInput) => {
|
|
32
|
+
if (payloadInput.daOutOfRange) {
|
|
33
|
+
return DataAvailabilityStatus.OutOfRange;
|
|
34
|
+
}
|
|
35
|
+
return payloadInput.getBlobKzgCommitments().length === 0
|
|
33
36
|
? DataAvailabilityStatus.NotRequired
|
|
34
|
-
: DataAvailabilityStatus.Available
|
|
35
|
-
);
|
|
37
|
+
: DataAvailabilityStatus.Available;
|
|
38
|
+
});
|
|
36
39
|
|
|
37
40
|
return {dataAvailabilityStatuses, availableTime};
|
|
38
41
|
}
|
package/src/chain/chain.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
getEffectiveBalancesFromStateBytes,
|
|
24
24
|
isStatePostAltair,
|
|
25
25
|
isStatePostElectra,
|
|
26
|
+
isStatePostGloas,
|
|
26
27
|
} from "@lodestar/state-transition";
|
|
27
28
|
import {
|
|
28
29
|
BeaconBlock,
|
|
@@ -335,13 +336,6 @@ export class BeaconChain implements IBeaconChain {
|
|
|
335
336
|
metrics,
|
|
336
337
|
logger,
|
|
337
338
|
});
|
|
338
|
-
this.seenPayloadEnvelopeInputCache = new SeenPayloadEnvelopeInput({
|
|
339
|
-
chainEvents: emitter,
|
|
340
|
-
signal,
|
|
341
|
-
serializedCache: this.serializedCache,
|
|
342
|
-
metrics,
|
|
343
|
-
logger,
|
|
344
|
-
});
|
|
345
339
|
|
|
346
340
|
this._earliestAvailableSlot = anchorState.slot;
|
|
347
341
|
|
|
@@ -397,6 +391,7 @@ export class BeaconChain implements IBeaconChain {
|
|
|
397
391
|
metrics,
|
|
398
392
|
logger
|
|
399
393
|
);
|
|
394
|
+
|
|
400
395
|
const regen = new QueuedStateRegenerator({
|
|
401
396
|
config,
|
|
402
397
|
forkChoice,
|
|
@@ -421,6 +416,33 @@ export class BeaconChain implements IBeaconChain {
|
|
|
421
416
|
this.payloadEnvelopeProcessor = new PayloadEnvelopeProcessor(this, metrics, signal);
|
|
422
417
|
|
|
423
418
|
this.forkChoice = forkChoice;
|
|
419
|
+
|
|
420
|
+
this.seenPayloadEnvelopeInputCache = new SeenPayloadEnvelopeInput({
|
|
421
|
+
config,
|
|
422
|
+
clock,
|
|
423
|
+
forkChoice,
|
|
424
|
+
chainEvents: emitter,
|
|
425
|
+
signal,
|
|
426
|
+
serializedCache: this.serializedCache,
|
|
427
|
+
metrics,
|
|
428
|
+
logger,
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
const anchorBlockSlot = anchorState.latestBlockHeader.slot;
|
|
432
|
+
if (isStatePostGloas(anchorState) && anchorBlockSlot > 0) {
|
|
433
|
+
const anchorBid = anchorState.latestExecutionPayloadBid;
|
|
434
|
+
this.seenPayloadEnvelopeInputCache.addFromBid({
|
|
435
|
+
blockRootHex: toRootHex(checkpoint.root),
|
|
436
|
+
slot: anchorBlockSlot,
|
|
437
|
+
forkName: anchorState.forkName,
|
|
438
|
+
proposerIndex: anchorState.latestBlockHeader.proposerIndex,
|
|
439
|
+
bid: anchorBid,
|
|
440
|
+
sampledColumns: this.custodyConfig.sampledColumns,
|
|
441
|
+
custodyColumns: this.custodyConfig.custodyColumns,
|
|
442
|
+
timeCreatedSec: Math.floor(Date.now() / 1000),
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
|
|
424
446
|
this.clock = clock;
|
|
425
447
|
this.regen = regen;
|
|
426
448
|
this.bls = bls;
|
package/src/chain/emitter.ts
CHANGED
|
@@ -4,7 +4,6 @@ import {routes} from "@lodestar/api";
|
|
|
4
4
|
import {CheckpointWithHex} from "@lodestar/fork-choice";
|
|
5
5
|
import {IBeaconStateView} from "@lodestar/state-transition";
|
|
6
6
|
import {DataColumnSidecar, RootHex, deneb, phase0} from "@lodestar/types";
|
|
7
|
-
import {SignedExecutionPayloadEnvelope} from "@lodestar/types/gloas";
|
|
8
7
|
import {PeerIdStr} from "../util/peerId.js";
|
|
9
8
|
import {BlockInputSource, IBlockInput} from "./blocks/blockInput/types.js";
|
|
10
9
|
import {PayloadEnvelopeInput} from "./blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
|
|
@@ -60,10 +59,6 @@ export enum ChainEvent {
|
|
|
60
59
|
* Post-gloas, missing parent could be a SignedBeaconBlock and/or a SignedExecutionPayloadEnvelope
|
|
61
60
|
*/
|
|
62
61
|
blockUnknownParent = "blockUnknownParent",
|
|
63
|
-
/**
|
|
64
|
-
* Trigger BlockInputSync to find a SignedBeaconBlock given a SignedExecutionPayloadEnvelop received
|
|
65
|
-
*/
|
|
66
|
-
envelopeUnknownBlock = "envelopeUnknownBlock",
|
|
67
62
|
/**
|
|
68
63
|
* Trigger BlockInputSync to find a SignedBeaconBlock with specified block root.
|
|
69
64
|
*/
|
|
@@ -92,11 +87,6 @@ type ApiEvents = {[K in routes.events.EventType]: (data: routes.events.EventData
|
|
|
92
87
|
|
|
93
88
|
export type ChainEventData = {
|
|
94
89
|
[ChainEvent.blockUnknownParent]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
|
|
95
|
-
[ChainEvent.envelopeUnknownBlock]: {
|
|
96
|
-
envelope: SignedExecutionPayloadEnvelope;
|
|
97
|
-
peer?: PeerIdStr;
|
|
98
|
-
source: BlockInputSource;
|
|
99
|
-
};
|
|
100
90
|
[ChainEvent.unknownBlockRoot]: {rootHex: RootHex; peer?: PeerIdStr; source: BlockInputSource};
|
|
101
91
|
[ChainEvent.incompleteBlockInput]: {blockInput: IBlockInput; peer: PeerIdStr; source: BlockInputSource};
|
|
102
92
|
[ChainEvent.incompletePayloadEnvelope]: {
|
|
@@ -124,7 +114,6 @@ export type IChainEvents = ApiEvents & {
|
|
|
124
114
|
// Sync events that are chain->chain. Initiated from network requests but do not cross the network
|
|
125
115
|
// barrier so are considered ChainEvent(s).
|
|
126
116
|
[ChainEvent.blockUnknownParent]: (data: ChainEventData[ChainEvent.blockUnknownParent]) => void;
|
|
127
|
-
[ChainEvent.envelopeUnknownBlock]: (data: ChainEventData[ChainEvent.envelopeUnknownBlock]) => void;
|
|
128
117
|
[ChainEvent.unknownBlockRoot]: (data: ChainEventData[ChainEvent.unknownBlockRoot]) => void;
|
|
129
118
|
[ChainEvent.incompleteBlockInput]: (data: ChainEventData[ChainEvent.incompleteBlockInput]) => void;
|
|
130
119
|
[ChainEvent.incompletePayloadEnvelope]: (data: ChainEventData[ChainEvent.incompletePayloadEnvelope]) => void;
|