@lodestar/beacon-node 1.43.0-rc.5 → 1.44.0-dev.1d0e0b9081
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/pool/index.d.ts.map +1 -1
- package/lib/api/impl/beacon/pool/index.js +46 -5
- package/lib/api/impl/beacon/pool/index.js.map +1 -1
- package/lib/api/impl/validator/index.d.ts.map +1 -1
- package/lib/api/impl/validator/index.js +26 -12
- package/lib/api/impl/validator/index.js.map +1 -1
- package/lib/chain/chain.d.ts +2 -1
- package/lib/chain/chain.d.ts.map +1 -1
- package/lib/chain/chain.js +3 -1
- package/lib/chain/chain.js.map +1 -1
- package/lib/chain/errors/executionPayloadBid.d.ts +19 -1
- package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/errors/executionPayloadBid.js +3 -0
- package/lib/chain/errors/executionPayloadBid.js.map +1 -1
- package/lib/chain/interface.d.ts +2 -1
- package/lib/chain/interface.d.ts.map +1 -1
- package/lib/chain/interface.js.map +1 -1
- package/lib/chain/lightClient/index.d.ts.map +1 -1
- package/lib/chain/lightClient/index.js +1 -1
- package/lib/chain/lightClient/index.js.map +1 -1
- package/lib/chain/opPools/index.d.ts +1 -0
- package/lib/chain/opPools/index.d.ts.map +1 -1
- package/lib/chain/opPools/index.js +1 -0
- package/lib/chain/opPools/index.js.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.d.ts +1 -1
- package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
- package/lib/chain/opPools/payloadAttestationPool.js +30 -10
- package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
- package/lib/chain/opPools/proposerPreferencesPool.d.ts +29 -0
- package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -0
- package/lib/chain/opPools/proposerPreferencesPool.js +56 -0
- package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -0
- package/lib/chain/produceBlock/produceBlockBody.d.ts +4 -0
- package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
- package/lib/chain/produceBlock/produceBlockBody.js +36 -1
- package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
- package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
- package/lib/chain/validation/executionPayloadBid.js +65 -17
- 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/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/network/gossip/topic.d.ts +20 -767
- 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 +8 -3
- package/lib/network/processor/gossipHandlers.js.map +1 -1
- package/lib/util/dependentRoot.d.ts +6 -2
- package/lib/util/dependentRoot.d.ts.map +1 -1
- package/lib/util/dependentRoot.js +20 -16
- package/lib/util/dependentRoot.js.map +1 -1
- package/package.json +14 -15
- package/src/api/impl/beacon/pool/index.ts +56 -3
- package/src/api/impl/validator/index.ts +28 -12
- package/src/chain/chain.ts +3 -0
- package/src/chain/errors/executionPayloadBid.ts +22 -1
- package/src/chain/interface.ts +2 -0
- package/src/chain/lightClient/index.ts +6 -6
- package/src/chain/opPools/index.ts +1 -0
- package/src/chain/opPools/payloadAttestationPool.ts +34 -10
- package/src/chain/opPools/proposerPreferencesPool.ts +59 -0
- package/src/chain/produceBlock/produceBlockBody.ts +59 -0
- package/src/chain/validation/executionPayloadBid.ts +68 -18
- package/src/chain/validation/payloadAttestationMessage.ts +6 -4
- package/src/execution/engine/interface.ts +1 -0
- package/src/execution/engine/types.ts +4 -0
- package/src/network/interface.ts +1 -0
- package/src/network/network.ts +11 -0
- package/src/network/processor/gossipHandlers.ts +8 -2
- package/src/util/dependentRoot.ts +22 -18
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
isStatePostGloas,
|
|
8
8
|
} from "@lodestar/state-transition";
|
|
9
9
|
import {gloas} from "@lodestar/types";
|
|
10
|
-
import {toRootHex} from "@lodestar/utils";
|
|
10
|
+
import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
|
|
11
|
+
import {getShufflingDependentRoot} from "../../util/dependentRoot.js";
|
|
11
12
|
import {ExecutionPayloadBidError, ExecutionPayloadBidErrorCode, GossipAction} from "../errors/index.js";
|
|
12
13
|
import {IBeaconChain} from "../index.js";
|
|
13
14
|
import {RegenCaller} from "../regen/index.js";
|
|
@@ -48,12 +49,55 @@ async function validateExecutionPayloadBid(
|
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
// [IGNORE] `bid.parent_block_root` is the hash tree root of a known beacon block in fork choice.
|
|
53
|
+
// Moved earlier than the spec ordering so we can derive the proposer dependent root for the
|
|
54
|
+
// proposer-preferences lookup below from a known fork-choice block.
|
|
55
|
+
const parentBlock = chain.forkChoice.getBlockHexDefaultStatus(parentBlockRootHex);
|
|
56
|
+
if (parentBlock === null) {
|
|
57
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
58
|
+
code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
59
|
+
parentBlockRoot: parentBlockRootHex,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
51
63
|
// [IGNORE] A `SignedProposerPreferences` matching `bid.slot` and the bid's branch has been
|
|
52
64
|
// seen — i.e. `proposal_slot == bid.slot` AND `dependent_root ==
|
|
53
|
-
// get_proposer_dependent_root(parent_state, compute_epoch_at_slot(bid.slot))
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
-
//
|
|
65
|
+
// get_proposer_dependent_root(parent_state, compute_epoch_at_slot(bid.slot))`.
|
|
66
|
+
const bidEpoch = computeEpochAtSlot(bid.slot);
|
|
67
|
+
// gloas is always post-Fulu, so `get_proposer_dependent_root` is the post-Fulu (deterministic
|
|
68
|
+
// proposer lookahead) form `block_root_at(start_slot(epoch - MIN_SEED_LOOKAHEAD) - 1)` with
|
|
69
|
+
// `MIN_SEED_LOOKAHEAD == 1` — identical to the attester-shuffling dependent root for the same
|
|
70
|
+
// epoch (both 1-epoch lookahead), hence `getShufflingDependentRoot`. `null` on a
|
|
71
|
+
// unknown/finalized-pruned ancestor or genesis edge → degrade to IGNORE below instead of
|
|
72
|
+
// letting a raw `ForkChoiceError` escape the `GossipActionError` contract.
|
|
73
|
+
const dependentRootHex = (() => {
|
|
74
|
+
try {
|
|
75
|
+
return getShufflingDependentRoot(chain.forkChoice, bidEpoch, computeEpochAtSlot(parentBlock.slot), parentBlock);
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
})();
|
|
80
|
+
|
|
81
|
+
if (dependentRootHex === null) {
|
|
82
|
+
// Could not derive the dependent root for this branch (unknown/finalized-pruned ancestor,
|
|
83
|
+
// genesis edge, etc.) → definitionally no matching `SignedProposerPreferences`.
|
|
84
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
85
|
+
code: ExecutionPayloadBidErrorCode.NO_MATCHING_PROPOSER_PREFERENCES,
|
|
86
|
+
slot: bid.slot,
|
|
87
|
+
parentBlockRoot: parentBlockRootHex,
|
|
88
|
+
dependentRoot: "unknown",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const proposerPreferences = chain.proposerPreferencesPool.get(bid.slot, dependentRootHex);
|
|
93
|
+
if (proposerPreferences === null) {
|
|
94
|
+
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
95
|
+
code: ExecutionPayloadBidErrorCode.NO_MATCHING_PROPOSER_PREFERENCES,
|
|
96
|
+
slot: bid.slot,
|
|
97
|
+
parentBlockRoot: parentBlockRootHex,
|
|
98
|
+
dependentRoot: dependentRootHex,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
57
101
|
|
|
58
102
|
// [REJECT] `bid.builder_index` is a valid/active builder index -- i.e.
|
|
59
103
|
// `is_active_builder(state, bid.builder_index)` returns `True`.
|
|
@@ -75,10 +119,25 @@ async function validateExecutionPayloadBid(
|
|
|
75
119
|
}
|
|
76
120
|
|
|
77
121
|
// [REJECT] `bid.fee_recipient == proposer_preferences.fee_recipient`.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
122
|
+
if (!byteArrayEquals(bid.feeRecipient, proposerPreferences.message.feeRecipient)) {
|
|
123
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
124
|
+
code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH,
|
|
125
|
+
builderIndex: bid.builderIndex,
|
|
126
|
+
bidFeeRecipient: toHex(bid.feeRecipient),
|
|
127
|
+
expectedFeeRecipient: toHex(proposerPreferences.message.feeRecipient),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// [REJECT] `bid.gas_limit == proposer_preferences.target_gas_limit`.
|
|
132
|
+
const bidGasLimit = Number(bid.gasLimit);
|
|
133
|
+
if (bidGasLimit !== proposerPreferences.message.targetGasLimit) {
|
|
134
|
+
throw new ExecutionPayloadBidError(GossipAction.REJECT, {
|
|
135
|
+
code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_GAS_LIMIT_MISMATCH,
|
|
136
|
+
builderIndex: bid.builderIndex,
|
|
137
|
+
bidGasLimit,
|
|
138
|
+
expectedGasLimit: proposerPreferences.message.targetGasLimit,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
82
141
|
|
|
83
142
|
// [REJECT] The length of KZG commitments is less than or equal to the limitation defined in the
|
|
84
143
|
// consensus layer -- i.e. validate that
|
|
@@ -128,15 +187,6 @@ async function validateExecutionPayloadBid(
|
|
|
128
187
|
// payload in fork choice.
|
|
129
188
|
// TODO GLOAS: implement this
|
|
130
189
|
|
|
131
|
-
// [IGNORE] `bid.parent_block_root` is the hash tree root of a known beacon
|
|
132
|
-
// block in fork choice.
|
|
133
|
-
if (!chain.forkChoice.hasBlock(bid.parentBlockRoot)) {
|
|
134
|
-
throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
|
|
135
|
-
code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT,
|
|
136
|
-
parentBlockRoot: parentBlockRootHex,
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
190
|
// [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
|
|
141
191
|
const signatureSet = createSingleSignatureSetFromComponents(
|
|
142
192
|
PublicKey.fromBytes(builder.pubkey),
|
|
@@ -11,7 +11,7 @@ import {IBeaconChain} from "../index.js";
|
|
|
11
11
|
|
|
12
12
|
export type PayloadAttestationValidationResult = {
|
|
13
13
|
attDataRootHex: RootHex;
|
|
14
|
-
|
|
14
|
+
validatorCommitteeIndices: number[];
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
export async function validateApiPayloadAttestationMessage(
|
|
@@ -80,9 +80,11 @@ async function validatePayloadAttestationMessage(
|
|
|
80
80
|
// [REJECT] The message's validator index is within the payload committee in
|
|
81
81
|
// `get_ptc(state, data.slot)`. The `state` is the head state corresponding to
|
|
82
82
|
// processing the block up to the current slot as determined by the fork choice.
|
|
83
|
-
|
|
83
|
+
// The validator may occupy multiple PTC positions because `compute_ptc` samples
|
|
84
|
+
// by effective balance — collect all of them so duplicate votes are counted.
|
|
85
|
+
const validatorCommitteeIndices = state.getIndicesInPayloadTimelinessCommittee(validatorIndex, data.slot);
|
|
84
86
|
|
|
85
|
-
if (
|
|
87
|
+
if (validatorCommitteeIndices.length === 0) {
|
|
86
88
|
throw new PayloadAttestationError(GossipAction.REJECT, {
|
|
87
89
|
code: PayloadAttestationErrorCode.INVALID_ATTESTER,
|
|
88
90
|
attesterIndex: validatorIndex,
|
|
@@ -115,6 +117,6 @@ async function validatePayloadAttestationMessage(
|
|
|
115
117
|
|
|
116
118
|
return {
|
|
117
119
|
attDataRootHex: toRootHex(ssz.gloas.PayloadAttestationData.hashTreeRoot(data)),
|
|
118
|
-
|
|
120
|
+
validatorCommitteeIndices,
|
|
119
121
|
};
|
|
120
122
|
}
|
|
@@ -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
|
|
package/src/network/interface.ts
CHANGED
|
@@ -114,6 +114,7 @@ export interface INetwork extends INetworkCorePublic {
|
|
|
114
114
|
publishLightClientOptimisticUpdate(update: LightClientOptimisticUpdate): Promise<number>;
|
|
115
115
|
publishSignedExecutionPayloadEnvelope(signedEnvelope: gloas.SignedExecutionPayloadEnvelope): Promise<number>;
|
|
116
116
|
publishPayloadAttestationMessage(payloadAttestationMessage: gloas.PayloadAttestationMessage): Promise<number>;
|
|
117
|
+
publishProposerPreferences(signedProposerPreferences: gloas.SignedProposerPreferences): Promise<number>;
|
|
117
118
|
|
|
118
119
|
// Debug
|
|
119
120
|
dumpGossipQueue(gossipType: GossipType): Promise<PendingGossipsubMessage[]>;
|
package/src/network/network.ts
CHANGED
|
@@ -526,6 +526,17 @@ export class Network implements INetwork {
|
|
|
526
526
|
);
|
|
527
527
|
}
|
|
528
528
|
|
|
529
|
+
async publishProposerPreferences(signedProposerPreferences: gloas.SignedProposerPreferences): Promise<number> {
|
|
530
|
+
const epoch = computeEpochAtSlot(signedProposerPreferences.message.proposalSlot);
|
|
531
|
+
const boundary = this.config.getForkBoundaryAtEpoch(epoch);
|
|
532
|
+
|
|
533
|
+
return this.publishGossip<GossipType.proposer_preferences>(
|
|
534
|
+
{type: GossipType.proposer_preferences, boundary},
|
|
535
|
+
signedProposerPreferences,
|
|
536
|
+
{ignoreDuplicatePublishError: true}
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
|
|
529
540
|
private async publishGossip<K extends GossipType>(
|
|
530
541
|
topic: GossipTopicMap[K],
|
|
531
542
|
object: GossipTypeMap[K],
|
|
@@ -1197,7 +1197,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1197
1197
|
const insertOutcome = chain.payloadAttestationPool.add(
|
|
1198
1198
|
payloadAttestationMessage,
|
|
1199
1199
|
validationResult.attDataRootHex,
|
|
1200
|
-
validationResult.
|
|
1200
|
+
validationResult.validatorCommitteeIndices
|
|
1201
1201
|
);
|
|
1202
1202
|
metrics?.opPool.payloadAttestationPool.gossipInsertOutcome.inc({insertOutcome});
|
|
1203
1203
|
} catch (e) {
|
|
@@ -1205,7 +1205,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1205
1205
|
}
|
|
1206
1206
|
chain.forkChoice.notifyPtcMessages(
|
|
1207
1207
|
toRootHex(payloadAttestationMessage.data.beaconBlockRoot),
|
|
1208
|
-
|
|
1208
|
+
validationResult.validatorCommitteeIndices,
|
|
1209
1209
|
payloadAttestationMessage.data.payloadPresent
|
|
1210
1210
|
);
|
|
1211
1211
|
},
|
|
@@ -1237,6 +1237,12 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
|
|
|
1237
1237
|
const {serializedData} = gossipData;
|
|
1238
1238
|
const signedProposerPreferences = sszDeserialize(topic, serializedData);
|
|
1239
1239
|
await validateGossipProposerPreferences(chain, signedProposerPreferences);
|
|
1240
|
+
|
|
1241
|
+
chain.proposerPreferencesPool.add(signedProposerPreferences);
|
|
1242
|
+
chain.emitter.emit(routes.events.EventType.proposerPreferences, {
|
|
1243
|
+
version: ForkName.gloas,
|
|
1244
|
+
data: signedProposerPreferences,
|
|
1245
|
+
});
|
|
1240
1246
|
},
|
|
1241
1247
|
};
|
|
1242
1248
|
}
|
|
@@ -2,45 +2,49 @@ import {EpochDifference, IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
|
|
|
2
2
|
import {Epoch, RootHex} from "@lodestar/types";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Get dependent root of a shuffling given
|
|
5
|
+
* Get dependent root of a shuffling given a message epoch and a proto block.
|
|
6
|
+
*
|
|
7
|
+
* Pre-gloas, this is used for attestation validation
|
|
8
|
+
* Post-gloas, this is also used for execution_payload_bid validation because post-fulu,
|
|
9
|
+
* a dependent root of a proposal duties is 1-epoch look ahead (instead of 0 as of pre-fulu)
|
|
6
10
|
*/
|
|
7
11
|
export function getShufflingDependentRoot(
|
|
8
12
|
forkChoice: IForkChoice,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
msgEpoch: Epoch,
|
|
14
|
+
protoBlockEpoch: Epoch,
|
|
15
|
+
protoBlock: ProtoBlock
|
|
12
16
|
): RootHex {
|
|
13
17
|
let shufflingDependentRoot: RootHex;
|
|
14
|
-
if (
|
|
18
|
+
if (protoBlockEpoch === msgEpoch) {
|
|
15
19
|
// current shuffling, this is equivalent to `headState.currentShuffling`
|
|
16
|
-
// given
|
|
20
|
+
// given protoBlockEpoch = msgEpoch = n
|
|
17
21
|
// epoch: (n-2) (n-1) n (n+1)
|
|
18
22
|
// |-------|-------|-------|-------|
|
|
19
|
-
//
|
|
23
|
+
// protoBlock ------------------------^
|
|
20
24
|
// shufflingDependentRoot ------^
|
|
21
|
-
shufflingDependentRoot = forkChoice.getDependentRoot(
|
|
22
|
-
} else if (
|
|
25
|
+
shufflingDependentRoot = forkChoice.getDependentRoot(protoBlock, EpochDifference.previous);
|
|
26
|
+
} else if (protoBlockEpoch === msgEpoch - 1) {
|
|
23
27
|
// next shuffling, this is equivalent to `headState.nextShuffling`
|
|
24
|
-
// given
|
|
28
|
+
// given protoBlockEpoch = n-1, msgEpoch = n
|
|
25
29
|
// epoch: (n-2) (n-1) n (n+1)
|
|
26
30
|
// |-------|-------|-------|-------|
|
|
27
|
-
//
|
|
31
|
+
// protoBlock -------------------^
|
|
28
32
|
// shufflingDependentRoot ------^
|
|
29
|
-
shufflingDependentRoot = forkChoice.getDependentRoot(
|
|
30
|
-
} else if (
|
|
33
|
+
shufflingDependentRoot = forkChoice.getDependentRoot(protoBlock, EpochDifference.current);
|
|
34
|
+
} else if (protoBlockEpoch < msgEpoch - 1) {
|
|
31
35
|
// this never happens with default chain option of maxSkipSlots = 32, however we still need to handle it
|
|
32
36
|
// check the verifyHeadBlockAndTargetRoot() function above
|
|
33
|
-
// given
|
|
37
|
+
// given protoBlockEpoch = n-2, msgEpoch = n
|
|
34
38
|
// epoch: (n-2) (n-1) n (n+1)
|
|
35
39
|
// |-------|-------|-------|-------|
|
|
36
|
-
//
|
|
40
|
+
// protoBlock -----------^
|
|
37
41
|
// shufflingDependentRoot -----^
|
|
38
|
-
shufflingDependentRoot =
|
|
42
|
+
shufflingDependentRoot = protoBlock.blockRoot;
|
|
39
43
|
// use lodestar_gossip_attestation_head_slot_to_attestation_slot metric to track this case
|
|
40
44
|
} else {
|
|
41
|
-
//
|
|
45
|
+
// protoBlockEpoch > msgEpoch
|
|
42
46
|
// should not happen, handled in verifyAttestationTargetRoot
|
|
43
|
-
throw Error(`
|
|
47
|
+
throw Error(`message epoch ${msgEpoch} is before proto block epoch ${protoBlockEpoch}`);
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
return shufflingDependentRoot;
|