@lodestar/state-transition 1.42.0-dev.5f2fffc2ce → 1.42.0-dev.687ecdc8cd
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/block/isValidIndexedAttestation.d.ts.map +1 -1
- package/lib/block/isValidIndexedAttestation.js +2 -3
- package/lib/block/isValidIndexedAttestation.js.map +1 -1
- package/lib/block/processAttestationsAltair.d.ts +2 -1
- package/lib/block/processAttestationsAltair.d.ts.map +1 -1
- package/lib/block/processAttestationsAltair.js +5 -3
- package/lib/block/processAttestationsAltair.js.map +1 -1
- package/lib/block/processExecutionPayloadEnvelope.d.ts +3 -1
- package/lib/block/processExecutionPayloadEnvelope.d.ts.map +1 -1
- package/lib/block/processExecutionPayloadEnvelope.js +11 -28
- package/lib/block/processExecutionPayloadEnvelope.js.map +1 -1
- package/lib/signatureSets/executionPayloadEnvelope.d.ts +5 -1
- package/lib/signatureSets/executionPayloadEnvelope.d.ts.map +1 -1
- package/lib/signatureSets/executionPayloadEnvelope.js +10 -1
- package/lib/signatureSets/executionPayloadEnvelope.js.map +1 -1
- package/lib/signatureSets/index.d.ts +2 -2
- package/lib/signatureSets/index.d.ts.map +1 -1
- package/lib/signatureSets/index.js +1 -2
- package/lib/signatureSets/index.js.map +1 -1
- package/lib/slot/upgradeStateToAltair.d.ts.map +1 -1
- package/lib/slot/upgradeStateToAltair.js +2 -1
- package/lib/slot/upgradeStateToAltair.js.map +1 -1
- package/lib/stateView/beaconStateView.d.ts +8 -10
- package/lib/stateView/beaconStateView.d.ts.map +1 -1
- package/lib/stateView/beaconStateView.js +11 -34
- package/lib/stateView/beaconStateView.js.map +1 -1
- package/lib/stateView/index.d.ts +1 -0
- package/lib/stateView/index.d.ts.map +1 -1
- package/lib/stateView/index.js +1 -0
- package/lib/stateView/index.js.map +1 -1
- package/lib/stateView/interface.d.ts +14 -9
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/stateViewFactory.d.ts +40 -0
- package/lib/stateView/stateViewFactory.d.ts.map +1 -0
- package/lib/stateView/stateViewFactory.js +46 -0
- package/lib/stateView/stateViewFactory.js.map +1 -0
- package/lib/util/execution.js +1 -1
- package/lib/util/execution.js.map +1 -1
- package/lib/util/rootCache.d.ts +2 -2
- package/lib/util/rootCache.d.ts.map +1 -1
- package/lib/util/rootCache.js +2 -3
- package/lib/util/rootCache.js.map +1 -1
- package/lib/util/shuffling.d.ts +2 -1
- package/lib/util/shuffling.d.ts.map +1 -1
- package/lib/util/shuffling.js +2 -2
- package/lib/util/shuffling.js.map +1 -1
- package/package.json +7 -7
- package/src/block/isValidIndexedAttestation.ts +2 -3
- package/src/block/processAttestationsAltair.ts +7 -4
- package/src/block/processExecutionPayloadEnvelope.ts +18 -35
- package/src/signatureSets/executionPayloadEnvelope.ts +26 -2
- package/src/signatureSets/index.ts +3 -4
- package/src/slot/upgradeStateToAltair.ts +2 -1
- package/src/stateView/beaconStateView.ts +27 -50
- package/src/stateView/index.ts +1 -0
- package/src/stateView/interface.ts +15 -6
- package/src/stateView/stateViewFactory.ts +78 -0
- package/src/util/execution.ts +1 -1
- package/src/util/rootCache.ts +4 -5
- package/src/util/shuffling.ts +5 -4
|
@@ -1,19 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
BUILDER_INDEX_SELF_BUILD,
|
|
4
|
-
DOMAIN_BEACON_BUILDER,
|
|
5
|
-
SLOTS_PER_EPOCH,
|
|
6
|
-
SLOTS_PER_HISTORICAL_ROOT,
|
|
7
|
-
} from "@lodestar/params";
|
|
1
|
+
import {SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
8
2
|
import {gloas, ssz} from "@lodestar/types";
|
|
9
3
|
import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
|
|
4
|
+
import {getExecutionPayloadEnvelopeSignatureSet} from "../signatureSets/executionPayloadEnvelope.js";
|
|
5
|
+
import {BeaconStateView} from "../stateView/beaconStateView.js";
|
|
10
6
|
import {CachedBeaconStateGloas} from "../types.js";
|
|
11
|
-
import {
|
|
7
|
+
import {computeTimeAtSlot} from "../util/index.js";
|
|
8
|
+
import {verifySignatureSet} from "../util/signatureSets.js";
|
|
12
9
|
import {processConsolidationRequest} from "./processConsolidationRequest.js";
|
|
13
10
|
import {processDepositRequest} from "./processDepositRequest.js";
|
|
14
11
|
import {processWithdrawalRequest} from "./processWithdrawalRequest.js";
|
|
15
12
|
|
|
16
13
|
export type ProcessExecutionPayloadEnvelopeOpts = {
|
|
14
|
+
verifySignature?: boolean;
|
|
15
|
+
verifyStateRoot?: boolean;
|
|
17
16
|
dontTransferCache?: boolean;
|
|
18
17
|
};
|
|
19
18
|
|
|
@@ -23,14 +22,14 @@ export type ProcessExecutionPayloadEnvelopeOpts = {
|
|
|
23
22
|
export function processExecutionPayloadEnvelope(
|
|
24
23
|
state: CachedBeaconStateGloas,
|
|
25
24
|
signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
|
|
26
|
-
verify: boolean,
|
|
27
25
|
opts?: ProcessExecutionPayloadEnvelopeOpts
|
|
28
26
|
): CachedBeaconStateGloas {
|
|
27
|
+
const {verifySignature = true, verifyStateRoot = true} = opts ?? {};
|
|
29
28
|
const envelope = signedEnvelope.message;
|
|
30
29
|
const payload = envelope.payload;
|
|
31
30
|
const fork = state.config.getForkSeq(envelope.slot);
|
|
32
31
|
|
|
33
|
-
if (
|
|
32
|
+
if (verifySignature && !verifyExecutionPayloadEnvelopeSignature(state, signedEnvelope)) {
|
|
34
33
|
throw Error(`Execution payload envelope has invalid signature builderIndex=${envelope.builderIndex}`);
|
|
35
34
|
}
|
|
36
35
|
|
|
@@ -70,7 +69,7 @@ export function processExecutionPayloadEnvelope(
|
|
|
70
69
|
|
|
71
70
|
postState.commit();
|
|
72
71
|
|
|
73
|
-
if (
|
|
72
|
+
if (verifyStateRoot && !byteArrayEquals(envelope.stateRoot, postState.hashTreeRoot())) {
|
|
74
73
|
throw new Error(
|
|
75
74
|
`Envelope's state root does not match state envelope=${toRootHex(envelope.stateRoot)} state=${toRootHex(postState.hashTreeRoot())}`
|
|
76
75
|
);
|
|
@@ -160,28 +159,12 @@ function verifyExecutionPayloadEnvelopeSignature(
|
|
|
160
159
|
state: CachedBeaconStateGloas,
|
|
161
160
|
signedEnvelope: gloas.SignedExecutionPayloadEnvelope
|
|
162
161
|
): boolean {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (builderIndex === BUILDER_INDEX_SELF_BUILD) {
|
|
172
|
-
const validatorIndex = state.latestBlockHeader.proposerIndex;
|
|
173
|
-
const proposerPubkey = state.epochCtx.pubkeyCache.get(validatorIndex);
|
|
174
|
-
if (!proposerPubkey) {
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
publicKey = proposerPubkey;
|
|
178
|
-
} else {
|
|
179
|
-
publicKey = PublicKey.fromBytes(state.builders.getReadonly(builderIndex).pubkey);
|
|
180
|
-
}
|
|
181
|
-
const signature = Signature.fromBytes(signedEnvelope.signature, true);
|
|
182
|
-
|
|
183
|
-
return verify(signingRoot, publicKey, signature);
|
|
184
|
-
} catch (_e) {
|
|
185
|
-
return false; // Catch all BLS errors: failed key validation, failed signature validation, invalid signature
|
|
186
|
-
}
|
|
162
|
+
const signatureSet = getExecutionPayloadEnvelopeSignatureSet(
|
|
163
|
+
state.config,
|
|
164
|
+
state.epochCtx.pubkeyCache,
|
|
165
|
+
new BeaconStateView(state),
|
|
166
|
+
signedEnvelope,
|
|
167
|
+
state.latestBlockHeader.proposerIndex
|
|
168
|
+
);
|
|
169
|
+
return verifySignatureSet(signatureSet);
|
|
187
170
|
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import {PublicKey} from "@chainsafe/blst";
|
|
1
2
|
import {BeaconConfig} from "@lodestar/config";
|
|
2
|
-
import {DOMAIN_BEACON_BUILDER} from "@lodestar/params";
|
|
3
|
-
import {gloas, ssz} from "@lodestar/types";
|
|
3
|
+
import {BUILDER_INDEX_SELF_BUILD, DOMAIN_BEACON_BUILDER} from "@lodestar/params";
|
|
4
|
+
import {ValidatorIndex, gloas, ssz} from "@lodestar/types";
|
|
5
|
+
import {PubkeyCache} from "../cache/pubkeyCache.js";
|
|
6
|
+
import {IBeaconStateView} from "../stateView/interface.js";
|
|
4
7
|
import {computeSigningRoot} from "../util/index.js";
|
|
8
|
+
import {type SingleSignatureSet, createSingleSignatureSetFromComponents} from "../util/signatureSets.js";
|
|
5
9
|
|
|
6
10
|
export function getExecutionPayloadEnvelopeSigningRoot(
|
|
7
11
|
config: BeaconConfig,
|
|
@@ -11,3 +15,23 @@ export function getExecutionPayloadEnvelopeSigningRoot(
|
|
|
11
15
|
|
|
12
16
|
return computeSigningRoot(ssz.gloas.ExecutionPayloadEnvelope, envelope, domain);
|
|
13
17
|
}
|
|
18
|
+
|
|
19
|
+
export function getExecutionPayloadEnvelopeSignatureSet(
|
|
20
|
+
config: BeaconConfig,
|
|
21
|
+
pubkeyCache: PubkeyCache,
|
|
22
|
+
state: IBeaconStateView,
|
|
23
|
+
signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
|
|
24
|
+
proposerIndex: ValidatorIndex
|
|
25
|
+
): SingleSignatureSet {
|
|
26
|
+
const envelope = signedEnvelope.message;
|
|
27
|
+
const pubkey =
|
|
28
|
+
envelope.builderIndex === BUILDER_INDEX_SELF_BUILD
|
|
29
|
+
? pubkeyCache.getOrThrow(proposerIndex)
|
|
30
|
+
: PublicKey.fromBytes(state.getBuilder(envelope.builderIndex).pubkey);
|
|
31
|
+
|
|
32
|
+
return createSingleSignatureSetFromComponents(
|
|
33
|
+
pubkey,
|
|
34
|
+
getExecutionPayloadEnvelopeSigningRoot(config, envelope),
|
|
35
|
+
signedEnvelope.signature
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -3,8 +3,7 @@ import {ForkSeq} from "@lodestar/params";
|
|
|
3
3
|
import {IndexedAttestation, SignedBeaconBlock, altair, capella} from "@lodestar/types";
|
|
4
4
|
import {getSyncCommitteeSignatureSet} from "../block/processSyncCommittee.js";
|
|
5
5
|
import {SyncCommitteeCache} from "../cache/syncCommitteeCache.js";
|
|
6
|
-
import {
|
|
7
|
-
import {CachedBeaconStateAllForks} from "../types.js";
|
|
6
|
+
import {IBeaconStateView} from "../stateView/interface.js";
|
|
8
7
|
import {ISignatureSet} from "../util/index.js";
|
|
9
8
|
import {getAttesterSlashingsSignatureSets} from "./attesterSlashings.js";
|
|
10
9
|
import {getBlsToExecutionChangeSignatureSets} from "./blsToExecutionChange.js";
|
|
@@ -32,7 +31,7 @@ export * from "./voluntaryExits.js";
|
|
|
32
31
|
export function getBlockSignatureSets(
|
|
33
32
|
config: BeaconConfig,
|
|
34
33
|
currentSyncCommitteeIndexed: SyncCommitteeCache,
|
|
35
|
-
state:
|
|
34
|
+
state: IBeaconStateView,
|
|
36
35
|
signedBlock: SignedBeaconBlock,
|
|
37
36
|
indexedAttestations: IndexedAttestation[],
|
|
38
37
|
opts?: {
|
|
@@ -48,7 +47,7 @@ export function getBlockSignatureSets(
|
|
|
48
47
|
...getProposerSlashingsSignatureSets(config, signedBlock),
|
|
49
48
|
...getAttesterSlashingsSignatureSets(config, signedBlock),
|
|
50
49
|
...getAttestationsSignatureSets(config, signedBlock, indexedAttestations),
|
|
51
|
-
...getVoluntaryExitsSignatureSets(config,
|
|
50
|
+
...getVoluntaryExitsSignatureSets(config, state, signedBlock),
|
|
52
51
|
];
|
|
53
52
|
|
|
54
53
|
if (!opts?.skipProposerSignature) {
|
|
@@ -3,6 +3,7 @@ import {ForkSeq} from "@lodestar/params";
|
|
|
3
3
|
import {ssz} from "@lodestar/types";
|
|
4
4
|
import {getAttestationParticipationStatus} from "../block/processAttestationsAltair.js";
|
|
5
5
|
import {getCachedBeaconState} from "../cache/stateCache.js";
|
|
6
|
+
import {BeaconStateView} from "../stateView/beaconStateView.js";
|
|
6
7
|
import {CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../types.js";
|
|
7
8
|
import {RootCache, newZeroedArray} from "../util/index.js";
|
|
8
9
|
import {getNextSyncCommittee} from "../util/syncCommittee.js";
|
|
@@ -125,7 +126,7 @@ function translateParticipation(
|
|
|
125
126
|
pendingAttesations: CompositeViewDU<typeof ssz.phase0.EpochAttestations>
|
|
126
127
|
): void {
|
|
127
128
|
const {epochCtx} = state;
|
|
128
|
-
const rootCache = new RootCache(state);
|
|
129
|
+
const rootCache = new RootCache(new BeaconStateView(state));
|
|
129
130
|
const epochParticipation = state.previousEpochParticipation;
|
|
130
131
|
|
|
131
132
|
for (const attestation of pendingAttesations.getAllReadonly()) {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {CompactMultiProof, ProofType, Tree, createProof} from "@chainsafe/persistent-merkle-tree";
|
|
2
|
-
import {ByteViews} from "@chainsafe/ssz";
|
|
2
|
+
import {BitArray, ByteViews} from "@chainsafe/ssz";
|
|
3
3
|
import {BeaconConfig} from "@lodestar/config";
|
|
4
4
|
import {ForkSeq, SLOTS_PER_HISTORICAL_ROOT, isForkPostGloas} from "@lodestar/params";
|
|
5
5
|
import {
|
|
6
6
|
BeaconBlock,
|
|
7
|
+
BeaconState,
|
|
7
8
|
BlindedBeaconBlock,
|
|
8
9
|
BuilderIndex,
|
|
9
10
|
Bytes32,
|
|
@@ -28,11 +29,11 @@ import {
|
|
|
28
29
|
} from "@lodestar/types";
|
|
29
30
|
import {Checkpoint, Fork} from "@lodestar/types/phase0";
|
|
30
31
|
import {processExecutionPayloadEnvelope} from "../block/index.js";
|
|
32
|
+
import {ProcessExecutionPayloadEnvelopeOpts} from "../block/processExecutionPayloadEnvelope.js";
|
|
31
33
|
import {VoluntaryExitValidity, getVoluntaryExitValidity} from "../block/processVoluntaryExit.js";
|
|
32
34
|
import {getExpectedWithdrawals} from "../block/processWithdrawals.js";
|
|
33
35
|
import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js";
|
|
34
36
|
import {EpochTransitionCacheOpts} from "../cache/epochTransitionCache.js";
|
|
35
|
-
import {PubkeyCache, createPubkeyCache} from "../cache/pubkeyCache.js";
|
|
36
37
|
import {RewardCache} from "../cache/rewardCache.js";
|
|
37
38
|
import {
|
|
38
39
|
CachedBeaconStateAllForks,
|
|
@@ -46,7 +47,6 @@ import {
|
|
|
46
47
|
isStateValidatorsNodesPopulated,
|
|
47
48
|
} from "../cache/stateCache.js";
|
|
48
49
|
import {SyncCommitteeCache} from "../cache/syncCommitteeCache.js";
|
|
49
|
-
import {BeaconStateAllForks} from "../cache/types.js";
|
|
50
50
|
import {computeUnrealizedCheckpoints} from "../epoch/computeUnrealizedCheckpoints.js";
|
|
51
51
|
import {getFinalizedRootProof, getSyncCommitteesWitness} from "../lightClient/proofs.js";
|
|
52
52
|
import {SyncCommitteeWitness} from "../lightClient/types.js";
|
|
@@ -63,7 +63,6 @@ import {isExecutionEnabled, isExecutionStateType, isMergeTransitionComplete} fro
|
|
|
63
63
|
import {canBuilderCoverBid} from "../util/gloas.js";
|
|
64
64
|
import {loadState} from "../util/loadState/loadState.js";
|
|
65
65
|
import {getRandaoMix} from "../util/seed.js";
|
|
66
|
-
import {getStateTypeFromBytes} from "../util/sszBytes.js";
|
|
67
66
|
import {getLatestWeakSubjectivityCheckpointEpoch} from "../util/weakSubjectivity.js";
|
|
68
67
|
import {IBeaconStateView} from "./interface.js";
|
|
69
68
|
|
|
@@ -91,7 +90,7 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
91
90
|
// fulu
|
|
92
91
|
private _proposerLookahead: fulu.ProposerLookahead | null = null;
|
|
93
92
|
// gloas
|
|
94
|
-
private _executionPayloadAvailability:
|
|
93
|
+
private _executionPayloadAvailability: BitArray | null = null;
|
|
95
94
|
private _latestExecutionPayloadBid: ExecutionPayloadBid | null = null;
|
|
96
95
|
|
|
97
96
|
constructor(readonly cachedState: CachedBeaconStateAllForks) {
|
|
@@ -356,15 +355,15 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
356
355
|
|
|
357
356
|
// gloas
|
|
358
357
|
|
|
359
|
-
get executionPayloadAvailability():
|
|
358
|
+
get executionPayloadAvailability(): BitArray {
|
|
360
359
|
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
361
360
|
throw new Error("executionPayloadAvailability is not available before GLOAS");
|
|
362
361
|
}
|
|
363
362
|
|
|
364
363
|
if (this._executionPayloadAvailability === null) {
|
|
365
|
-
this._executionPayloadAvailability = (
|
|
366
|
-
.
|
|
367
|
-
|
|
364
|
+
this._executionPayloadAvailability = (
|
|
365
|
+
this.cachedState as CachedBeaconStateGloas
|
|
366
|
+
).executionPayloadAvailability.toValue();
|
|
368
367
|
}
|
|
369
368
|
|
|
370
369
|
return this._executionPayloadAvailability;
|
|
@@ -403,7 +402,7 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
403
402
|
* Return the index of the validator in the PTC committee for the given slot.
|
|
404
403
|
* return -1 if validator is not in the PTC committee for the given slot.
|
|
405
404
|
*/
|
|
406
|
-
|
|
405
|
+
getIndexInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number {
|
|
407
406
|
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
408
407
|
throw new Error("PTC committees are not supported before GLOAS");
|
|
409
408
|
}
|
|
@@ -502,6 +501,10 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
502
501
|
return this.cachedState.epochCtx.syncProposerReward;
|
|
503
502
|
}
|
|
504
503
|
|
|
504
|
+
getIndexedSyncCommittee(slot: Slot): SyncCommitteeCache {
|
|
505
|
+
return this.cachedState.epochCtx.getIndexedSyncCommittee(slot);
|
|
506
|
+
}
|
|
507
|
+
|
|
505
508
|
getIndexedSyncCommitteeAtEpoch(epoch: Epoch): SyncCommitteeCache {
|
|
506
509
|
return this.cachedState.epochCtx.getIndexedSyncCommitteeAtEpoch(epoch);
|
|
507
510
|
}
|
|
@@ -712,6 +715,10 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
712
715
|
return new BeaconStateView(cachedState);
|
|
713
716
|
}
|
|
714
717
|
|
|
718
|
+
toValue(): BeaconState {
|
|
719
|
+
return this.cachedState.toValue();
|
|
720
|
+
}
|
|
721
|
+
|
|
715
722
|
serialize(): Uint8Array {
|
|
716
723
|
return this.cachedState.serialize();
|
|
717
724
|
}
|
|
@@ -761,49 +768,19 @@ export class BeaconStateView implements IBeaconStateView {
|
|
|
761
768
|
return new BeaconStateView(newState);
|
|
762
769
|
}
|
|
763
770
|
|
|
764
|
-
processExecutionPayloadEnvelope(
|
|
771
|
+
processExecutionPayloadEnvelope(
|
|
772
|
+
signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
|
|
773
|
+
opts?: ProcessExecutionPayloadEnvelopeOpts
|
|
774
|
+
): BeaconStateView {
|
|
765
775
|
const fork = this.config.getForkName(this.cachedState.slot);
|
|
766
776
|
if (!isForkPostGloas(fork)) {
|
|
767
777
|
throw Error(`processExecutionPayloadEnvelope is only available for gloas+ forks, got fork=${fork}`);
|
|
768
778
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
*/
|
|
776
|
-
export function createBeaconStateViewForHistoricalRegen(
|
|
777
|
-
config: BeaconConfig,
|
|
778
|
-
stateBytes: Uint8Array
|
|
779
|
-
): IBeaconStateView {
|
|
780
|
-
const state = getStateTypeFromBytes(config, stateBytes).deserializeToViewDU(stateBytes);
|
|
781
|
-
|
|
782
|
-
const pubkeyCache = createPubkeyCache();
|
|
783
|
-
syncPubkeyCache(state, pubkeyCache);
|
|
784
|
-
const cachedState = createCachedBeaconState(
|
|
785
|
-
state,
|
|
786
|
-
{
|
|
787
|
-
config,
|
|
788
|
-
pubkeyCache,
|
|
789
|
-
},
|
|
790
|
-
{
|
|
791
|
-
skipSyncPubkeys: true,
|
|
792
|
-
}
|
|
793
|
-
);
|
|
794
|
-
|
|
795
|
-
return new BeaconStateView(cachedState);
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
/**
|
|
799
|
-
* Populate a PubkeyIndexMap with any new entries based on a BeaconState
|
|
800
|
-
*/
|
|
801
|
-
function syncPubkeyCache(state: BeaconStateAllForks, pubkeyCache: PubkeyCache): void {
|
|
802
|
-
// Get the validators sub tree once for all the loop
|
|
803
|
-
|
|
804
|
-
const newCount = state.validators.length;
|
|
805
|
-
for (let i = pubkeyCache.size; i < newCount; i++) {
|
|
806
|
-
const pubkey = state.validators.getReadonly(i).pubkey;
|
|
807
|
-
pubkeyCache.set(i, pubkey);
|
|
779
|
+
const postPayloadState = processExecutionPayloadEnvelope(
|
|
780
|
+
this.cachedState as CachedBeaconStateGloas,
|
|
781
|
+
signedEnvelope,
|
|
782
|
+
opts
|
|
783
|
+
);
|
|
784
|
+
return new BeaconStateView(postPayloadState);
|
|
808
785
|
}
|
|
809
786
|
}
|
package/src/stateView/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {CompactMultiProof} from "@chainsafe/persistent-merkle-tree";
|
|
2
|
-
import {ByteViews} from "@chainsafe/ssz";
|
|
2
|
+
import {BitArray, ByteViews} from "@chainsafe/ssz";
|
|
3
3
|
import {
|
|
4
4
|
BeaconBlock,
|
|
5
|
+
BeaconState,
|
|
5
6
|
BlindedBeaconBlock,
|
|
6
7
|
BuilderIndex,
|
|
7
8
|
Bytes32,
|
|
@@ -23,6 +24,7 @@ import {
|
|
|
23
24
|
rewards,
|
|
24
25
|
} from "@lodestar/types";
|
|
25
26
|
import {Checkpoint, Fork} from "@lodestar/types/phase0";
|
|
27
|
+
import {ProcessExecutionPayloadEnvelopeOpts} from "../block/processExecutionPayloadEnvelope.js";
|
|
26
28
|
import {VoluntaryExitValidity} from "../block/processVoluntaryExit.js";
|
|
27
29
|
import {EffectiveBalanceIncrements} from "../cache/effectiveBalanceIncrements.js";
|
|
28
30
|
import {EpochTransitionCacheOpts} from "../cache/epochTransitionCache.js";
|
|
@@ -92,11 +94,11 @@ export interface IBeaconStateView {
|
|
|
92
94
|
proposerLookahead: fulu.ProposerLookahead;
|
|
93
95
|
|
|
94
96
|
// gloas
|
|
95
|
-
executionPayloadAvailability:
|
|
97
|
+
executionPayloadAvailability: BitArray;
|
|
96
98
|
latestExecutionPayloadBid: ExecutionPayloadBid;
|
|
97
99
|
getBuilder(index: BuilderIndex): gloas.Builder;
|
|
98
100
|
canBuilderCoverBid(builderIndex: BuilderIndex, bidAmount: number): boolean;
|
|
99
|
-
|
|
101
|
+
getIndexInPayloadTimelinessCommittee(validatorIndex: ValidatorIndex, slot: Slot): number;
|
|
100
102
|
|
|
101
103
|
// Shuffling and committees
|
|
102
104
|
getShufflingAtEpoch(epoch: Epoch): EpochShuffling;
|
|
@@ -109,12 +111,11 @@ export interface IBeaconStateView {
|
|
|
109
111
|
getCurrentShuffling(): EpochShuffling;
|
|
110
112
|
getNextShuffling(): EpochShuffling;
|
|
111
113
|
|
|
112
|
-
//
|
|
114
|
+
// Proposer shuffling
|
|
113
115
|
previousProposers: ValidatorIndex[] | null;
|
|
114
116
|
currentProposers: ValidatorIndex[];
|
|
115
117
|
nextProposers: ValidatorIndex[];
|
|
116
118
|
getBeaconProposer(slot: Slot): ValidatorIndex;
|
|
117
|
-
computeAnchorCheckpoint(): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader};
|
|
118
119
|
|
|
119
120
|
// Sync committees
|
|
120
121
|
currentSyncCommittee: altair.SyncCommittee;
|
|
@@ -122,6 +123,8 @@ export interface IBeaconStateView {
|
|
|
122
123
|
currentSyncCommitteeIndexed: SyncCommitteeCache;
|
|
123
124
|
syncProposerReward: number;
|
|
124
125
|
getIndexedSyncCommitteeAtEpoch(epoch: Epoch): SyncCommitteeCache;
|
|
126
|
+
/** Get indexed sync committee with slot+1 offset for duty lookups */
|
|
127
|
+
getIndexedSyncCommittee(slot: Slot): SyncCommitteeCache;
|
|
125
128
|
|
|
126
129
|
// Validators and balances
|
|
127
130
|
effectiveBalanceIncrements: EffectiveBalanceIncrements;
|
|
@@ -148,6 +151,7 @@ export interface IBeaconStateView {
|
|
|
148
151
|
expectedWithdrawals: capella.Withdrawal[];
|
|
149
152
|
processedBuilderWithdrawalsCount: number;
|
|
150
153
|
processedPartialWithdrawalsCount: number;
|
|
154
|
+
processedBuildersSweepCount: number;
|
|
151
155
|
processedValidatorSweepCount: number;
|
|
152
156
|
};
|
|
153
157
|
|
|
@@ -179,6 +183,7 @@ export interface IBeaconStateView {
|
|
|
179
183
|
justifiedCheckpoint: phase0.Checkpoint;
|
|
180
184
|
finalizedCheckpoint: phase0.Checkpoint;
|
|
181
185
|
};
|
|
186
|
+
computeAnchorCheckpoint(): {checkpoint: phase0.Checkpoint; blockHeader: phase0.BeaconBlockHeader};
|
|
182
187
|
|
|
183
188
|
// this is for backward compatible
|
|
184
189
|
clonedCount: number;
|
|
@@ -189,6 +194,7 @@ export interface IBeaconStateView {
|
|
|
189
194
|
|
|
190
195
|
// Serialization
|
|
191
196
|
loadOtherState(stateBytes: Uint8Array, seedValidatorsBytes?: Uint8Array): IBeaconStateView;
|
|
197
|
+
toValue(): BeaconState;
|
|
192
198
|
serialize(): Uint8Array;
|
|
193
199
|
serializedSize(): number;
|
|
194
200
|
serializeToBytes(output: ByteViews, offset: number): number;
|
|
@@ -209,5 +215,8 @@ export interface IBeaconStateView {
|
|
|
209
215
|
epochTransitionCacheOpts?: EpochTransitionCacheOpts & {dontTransferCache?: boolean},
|
|
210
216
|
modules?: StateTransitionModules
|
|
211
217
|
): IBeaconStateView;
|
|
212
|
-
processExecutionPayloadEnvelope(
|
|
218
|
+
processExecutionPayloadEnvelope(
|
|
219
|
+
signedEnvelope: gloas.SignedExecutionPayloadEnvelope,
|
|
220
|
+
opts?: ProcessExecutionPayloadEnvelopeOpts
|
|
221
|
+
): IBeaconStateView;
|
|
213
222
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {BeaconConfig} from "@lodestar/config";
|
|
2
|
+
import {PubkeyCache, createPubkeyCache} from "../cache/pubkeyCache.js";
|
|
3
|
+
import {createCachedBeaconState} from "../cache/stateCache.js";
|
|
4
|
+
import {BeaconStateAllForks} from "../cache/types.js";
|
|
5
|
+
import {getStateTypeFromBytes} from "../util/sszBytes.js";
|
|
6
|
+
import {BeaconStateView} from "./beaconStateView.js";
|
|
7
|
+
import {IBeaconStateView} from "./interface.js";
|
|
8
|
+
|
|
9
|
+
// ---- createBeaconStateView (startup path) ----
|
|
10
|
+
|
|
11
|
+
type NodeJSOpts = {
|
|
12
|
+
useNative: false;
|
|
13
|
+
anchorState: BeaconStateAllForks;
|
|
14
|
+
config: BeaconConfig;
|
|
15
|
+
pubkeyCache: PubkeyCache;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type NativeOpts = {
|
|
19
|
+
useNative: true;
|
|
20
|
+
stateBytes: Uint8Array;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Create a BeaconStateView from a pre-deserialized state. Used at node startup.
|
|
25
|
+
*
|
|
26
|
+
* The caller is responsible for creating and populating `pubkeyCache` (it is also
|
|
27
|
+
* passed separately to BeaconNode.init, so it must live outside this factory).
|
|
28
|
+
*
|
|
29
|
+
* Set `useNative: true` to use the native (Zig) implementation once available.
|
|
30
|
+
*/
|
|
31
|
+
export function createBeaconStateView(opts: NodeJSOpts | NativeOpts): IBeaconStateView {
|
|
32
|
+
if (opts.useNative) {
|
|
33
|
+
throw new Error("Native (Zig) BeaconStateView not yet implemented");
|
|
34
|
+
}
|
|
35
|
+
const {anchorState, config, pubkeyCache} = opts;
|
|
36
|
+
const cachedState = createCachedBeaconState(anchorState, {config, pubkeyCache}, {skipSyncPubkeys: true});
|
|
37
|
+
return new BeaconStateView(cachedState);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ---- createBeaconStateViewForHistoricalRegen (regen path) ----
|
|
41
|
+
|
|
42
|
+
// Reused across all historical state regen calls in the worker thread
|
|
43
|
+
const pubkeyCacheRegen = createPubkeyCache();
|
|
44
|
+
|
|
45
|
+
function syncPubkeyCache(state: BeaconStateAllForks, pubkeyCache: PubkeyCache): void {
|
|
46
|
+
const newCount = state.validators.length;
|
|
47
|
+
for (let i = pubkeyCache.size; i < newCount; i++) {
|
|
48
|
+
const pubkey = state.validators.getReadonly(i).pubkey;
|
|
49
|
+
pubkeyCache.set(i, pubkey);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type RegenNodeJSOpts = {
|
|
54
|
+
useNative: false;
|
|
55
|
+
config: BeaconConfig;
|
|
56
|
+
stateBytes: Uint8Array;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
type RegenNativeOpts = {
|
|
60
|
+
useNative: true;
|
|
61
|
+
stateBytes: Uint8Array;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create a BeaconStateView from raw SSZ bytes. Used in the historical state regen worker thread.
|
|
66
|
+
*
|
|
67
|
+
* Set `useNative: true` to use the native (Zig) implementation once available.
|
|
68
|
+
*/
|
|
69
|
+
export function createBeaconStateViewForHistoricalRegen(opts: RegenNodeJSOpts | RegenNativeOpts): IBeaconStateView {
|
|
70
|
+
if (opts.useNative) {
|
|
71
|
+
throw new Error("Native (Zig) BeaconStateView not yet implemented");
|
|
72
|
+
}
|
|
73
|
+
const {config, stateBytes} = opts;
|
|
74
|
+
const state = getStateTypeFromBytes(config, stateBytes).deserializeToViewDU(stateBytes);
|
|
75
|
+
syncPubkeyCache(state, pubkeyCacheRegen);
|
|
76
|
+
const cachedState = createCachedBeaconState(state, {config, pubkeyCache: pubkeyCacheRegen}, {skipSyncPubkeys: true});
|
|
77
|
+
return new BeaconStateView(cachedState);
|
|
78
|
+
}
|
package/src/util/execution.ts
CHANGED
|
@@ -143,7 +143,7 @@ export function executionPayloadToPayloadHeader(fork: ForkSeq, payload: Executio
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
if (fork >= ForkSeq.deneb) {
|
|
146
|
-
// https://github.com/ethereum/consensus-specs/blob/
|
|
146
|
+
// https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.2/specs/eip4844/beacon-chain.md#process_execution_payload
|
|
147
147
|
(bellatrixPayloadFields as deneb.ExecutionPayloadHeader).blobGasUsed = (
|
|
148
148
|
payload as deneb.ExecutionPayloadHeader | deneb.ExecutionPayload
|
|
149
149
|
).blobGasUsed;
|
package/src/util/rootCache.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {Epoch, Root, Slot, phase0} from "@lodestar/types";
|
|
2
|
-
import {
|
|
3
|
-
import {getBlockRoot, getBlockRootAtSlot} from "./blockRoot.js";
|
|
2
|
+
import {IBeaconStateView} from "../stateView/interface.js";
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Cache to prevent accessing the state tree to fetch block roots repeteadly.
|
|
@@ -12,7 +11,7 @@ export class RootCache {
|
|
|
12
11
|
private readonly blockRootEpochCache = new Map<Epoch, Root>();
|
|
13
12
|
private readonly blockRootSlotCache = new Map<Slot, Root>();
|
|
14
13
|
|
|
15
|
-
constructor(private readonly state:
|
|
14
|
+
constructor(private readonly state: IBeaconStateView) {
|
|
16
15
|
this.currentJustifiedCheckpoint = state.currentJustifiedCheckpoint;
|
|
17
16
|
this.previousJustifiedCheckpoint = state.previousJustifiedCheckpoint;
|
|
18
17
|
}
|
|
@@ -20,7 +19,7 @@ export class RootCache {
|
|
|
20
19
|
getBlockRoot(epoch: Epoch): Root {
|
|
21
20
|
let root = this.blockRootEpochCache.get(epoch);
|
|
22
21
|
if (!root) {
|
|
23
|
-
root =
|
|
22
|
+
root = this.state.getBlockRootAtEpoch(epoch);
|
|
24
23
|
this.blockRootEpochCache.set(epoch, root);
|
|
25
24
|
}
|
|
26
25
|
return root;
|
|
@@ -29,7 +28,7 @@ export class RootCache {
|
|
|
29
28
|
getBlockRootAtSlot(slot: Slot): Root {
|
|
30
29
|
let root = this.blockRootSlotCache.get(slot);
|
|
31
30
|
if (!root) {
|
|
32
|
-
root =
|
|
31
|
+
root = this.state.getBlockRootAtSlot(slot);
|
|
33
32
|
this.blockRootSlotCache.set(slot, root);
|
|
34
33
|
}
|
|
35
34
|
return root;
|
package/src/util/shuffling.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "@lodestar/types";
|
|
12
12
|
import {LodestarError} from "@lodestar/utils";
|
|
13
13
|
import {CachedBeaconStateAllForks} from "../cache/stateCache.js";
|
|
14
|
+
import {IBeaconStateView} from "../stateView/interface.js";
|
|
14
15
|
import {getBlockRootAtSlot} from "./blockRoot.js";
|
|
15
16
|
import {computeStartSlotAtEpoch} from "./epoch.js";
|
|
16
17
|
import {EpochShuffling} from "./epochShuffling.js";
|
|
@@ -22,21 +23,21 @@ import {EpochShuffling} from "./epochShuffling.js";
|
|
|
22
23
|
* Returns `null` on the one-off scenario where the genesis block decides its own shuffling.
|
|
23
24
|
* It should be set to the latest block applied to this `state` or the genesis block root.
|
|
24
25
|
*/
|
|
25
|
-
export function proposerShufflingDecisionRoot(fork: ForkName, state:
|
|
26
|
+
export function proposerShufflingDecisionRoot(fork: ForkName, state: IBeaconStateView): Root | null {
|
|
26
27
|
const decisionSlot = proposerShufflingDecisionSlot(fork, state);
|
|
27
28
|
if (state.slot === decisionSlot) {
|
|
28
29
|
return null;
|
|
29
30
|
}
|
|
30
|
-
return getBlockRootAtSlot(
|
|
31
|
+
return state.getBlockRootAtSlot(decisionSlot);
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
35
|
* Returns the slot at which the proposer shuffling was decided. The block root at this slot
|
|
35
36
|
* can be used to key the proposer shuffling for the current epoch.
|
|
36
37
|
*/
|
|
37
|
-
function proposerShufflingDecisionSlot(fork: ForkName, state:
|
|
38
|
+
function proposerShufflingDecisionSlot(fork: ForkName, state: IBeaconStateView): Slot {
|
|
38
39
|
// After fulu, the decision slot is in previous epoch due to deterministic proposer lookahead
|
|
39
|
-
const epoch = isForkPostFulu(fork) ? state.
|
|
40
|
+
const epoch = isForkPostFulu(fork) ? state.epoch - 1 : state.epoch;
|
|
40
41
|
const startSlot = computeStartSlotAtEpoch(epoch);
|
|
41
42
|
return Math.max(startSlot - 1, 0);
|
|
42
43
|
}
|