@lodestar/state-transition 1.44.0-rc.2 → 1.44.0
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/index.d.ts +2 -0
- package/lib/block/index.d.ts.map +1 -1
- package/lib/block/index.js +3 -1
- package/lib/block/index.js.map +1 -1
- package/lib/block/processBuilderDepositRequest.d.ts +10 -0
- package/lib/block/processBuilderDepositRequest.d.ts.map +1 -0
- package/lib/block/processBuilderDepositRequest.js +27 -0
- package/lib/block/processBuilderDepositRequest.js.map +1 -0
- package/lib/block/processBuilderExitRequest.d.ts +13 -0
- package/lib/block/processBuilderExitRequest.d.ts.map +1 -0
- package/lib/block/processBuilderExitRequest.js +29 -0
- package/lib/block/processBuilderExitRequest.js.map +1 -0
- package/lib/block/processDepositRequest.d.ts +2 -8
- package/lib/block/processDepositRequest.d.ts.map +1 -1
- package/lib/block/processDepositRequest.js +2 -98
- package/lib/block/processDepositRequest.js.map +1 -1
- package/lib/block/processExecutionPayloadBid.d.ts +2 -3
- package/lib/block/processExecutionPayloadBid.d.ts.map +1 -1
- package/lib/block/processExecutionPayloadBid.js +16 -8
- package/lib/block/processExecutionPayloadBid.js.map +1 -1
- package/lib/block/processParentExecutionPayload.d.ts +2 -2
- package/lib/block/processParentExecutionPayload.d.ts.map +1 -1
- package/lib/block/processParentExecutionPayload.js +16 -8
- package/lib/block/processParentExecutionPayload.js.map +1 -1
- package/lib/block/processProposerSlashing.d.ts.map +1 -1
- package/lib/block/processProposerSlashing.js +9 -1
- package/lib/block/processProposerSlashing.js.map +1 -1
- package/lib/block/processVoluntaryExit.d.ts +1 -1
- package/lib/block/processVoluntaryExit.d.ts.map +1 -1
- package/lib/block/processVoluntaryExit.js +1 -35
- package/lib/block/processVoluntaryExit.js.map +1 -1
- package/lib/slot/upgradeStateToGloas.js +34 -28
- package/lib/slot/upgradeStateToGloas.js.map +1 -1
- package/lib/stateView/beaconStateView.d.ts +1 -1
- package/lib/stateView/beaconStateView.d.ts.map +1 -1
- package/lib/stateView/beaconStateView.js.map +1 -1
- package/lib/stateView/interface.d.ts +1 -1
- package/lib/stateView/interface.d.ts.map +1 -1
- package/lib/stateView/nativeBeaconStateView.d.ts +1 -1
- package/lib/stateView/nativeBeaconStateView.d.ts.map +1 -1
- package/lib/stateView/nativeBeaconStateView.js.map +1 -1
- package/lib/util/gloas.d.ts +17 -0
- package/lib/util/gloas.d.ts.map +1 -1
- package/lib/util/gloas.js +59 -1
- package/lib/util/gloas.js.map +1 -1
- package/package.json +7 -7
- package/src/block/index.ts +6 -1
- package/src/block/processBuilderDepositRequest.ts +43 -0
- package/src/block/processBuilderExitRequest.ts +39 -0
- package/src/block/processDepositRequest.ts +3 -124
- package/src/block/processExecutionPayloadBid.ts +24 -9
- package/src/block/processParentExecutionPayload.ts +23 -11
- package/src/block/processProposerSlashing.ts +9 -4
- package/src/block/processVoluntaryExit.ts +2 -61
- package/src/slot/upgradeStateToGloas.ts +48 -32
- package/src/stateView/beaconStateView.ts +1 -1
- package/src/stateView/interface.ts +1 -1
- package/src/stateView/nativeBeaconStateView.ts +1 -1
- package/src/util/gloas.ts +76 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
1
|
+
import {PAYLOAD_BUILDER_VERSION, SLOTS_PER_HISTORICAL_ROOT} from "@lodestar/params";
|
|
2
2
|
import {ssz} from "@lodestar/types";
|
|
3
3
|
import {toPubkeyHex} from "@lodestar/utils";
|
|
4
|
-
import {
|
|
4
|
+
import {isValidDepositSignature} from "../block/processDeposit.js";
|
|
5
5
|
import {getCachedBeaconState} from "../cache/stateCache.js";
|
|
6
6
|
import {CachedBeaconStateFulu, CachedBeaconStateGloas} from "../types.js";
|
|
7
|
-
import {initializePtcWindow, isBuilderWithdrawalCredential} from "../util/gloas.js";
|
|
7
|
+
import {addBuilderToRegistry, initializePtcWindow, isBuilderWithdrawalCredential} from "../util/gloas.js";
|
|
8
8
|
import {isValidatorKnown} from "../util/index.js";
|
|
9
9
|
import {PendingDepositsLookup} from "../util/pendingDepositsLookup.js";
|
|
10
10
|
|
|
@@ -49,8 +49,8 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
|
|
|
49
49
|
stateGloasView.nextSyncCommittee = stateGloasCloned.nextSyncCommittee;
|
|
50
50
|
stateGloasView.latestExecutionPayloadBid.blockHash = stateFulu.latestExecutionPayloadHeader.blockHash;
|
|
51
51
|
stateGloasView.latestExecutionPayloadBid.gasLimit = stateFulu.latestExecutionPayloadHeader.gasLimit;
|
|
52
|
-
stateGloasView.latestExecutionPayloadBid.executionRequestsRoot = ssz.
|
|
53
|
-
ssz.
|
|
52
|
+
stateGloasView.latestExecutionPayloadBid.executionRequestsRoot = ssz.gloas.ExecutionRequests.hashTreeRoot(
|
|
53
|
+
ssz.gloas.ExecutionRequests.defaultValue()
|
|
54
54
|
);
|
|
55
55
|
stateGloasView.nextWithdrawalIndex = stateGloasCloned.nextWithdrawalIndex;
|
|
56
56
|
stateGloasView.nextWithdrawalValidatorIndex = stateGloasCloned.nextWithdrawalValidatorIndex;
|
|
@@ -90,7 +90,8 @@ export function upgradeStateToGloas(stateFulu: CachedBeaconStateFulu): CachedBea
|
|
|
90
90
|
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.8/specs/gloas/fork.md#new-onboard_builders_from_pending_deposits
|
|
91
91
|
*/
|
|
92
92
|
function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void {
|
|
93
|
-
// Track pubkeys of new builders added when applying deposits
|
|
93
|
+
// Track pubkeys of new builders added when applying deposits. `state.builders` starts empty
|
|
94
|
+
// at the fork, so every builder pubkey here is one added in an earlier iteration.
|
|
94
95
|
const builderPubkeys = new Set<string>();
|
|
95
96
|
|
|
96
97
|
const pendingDeposits = ssz.electra.PendingDeposits.defaultViewDU();
|
|
@@ -109,40 +110,55 @@ function onboardBuildersFromPendingDeposits(state: CachedBeaconStateGloas): void
|
|
|
109
110
|
continue;
|
|
110
111
|
}
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (!isBuilderWithdrawalCredential(deposit.withdrawalCredentials)) {
|
|
121
|
-
pendingDeposits.push(deposit);
|
|
122
|
-
pendingDepositsLookup.add(deposit, pubkeyHex);
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
if (pendingDepositsLookup.hasPendingValidator(state.config, pubkeyHex)) {
|
|
126
|
-
pendingDeposits.push(deposit);
|
|
127
|
-
pendingDepositsLookup.add(deposit, pubkeyHex);
|
|
128
|
-
continue;
|
|
113
|
+
if (builderPubkeys.has(pubkeyHex)) {
|
|
114
|
+
// Top up an already-onboarded builder
|
|
115
|
+
// TODO GLOAS: linear search; consider builder pubkey cache when we drop the upgrade-time set
|
|
116
|
+
for (let j = 0; j < state.builders.length; j++) {
|
|
117
|
+
if (toPubkeyHex(state.builders.getReadonly(j).pubkey) === pubkeyHex) {
|
|
118
|
+
state.builders.get(j).balance += deposit.amount;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
129
121
|
}
|
|
122
|
+
continue;
|
|
130
123
|
}
|
|
131
124
|
|
|
132
|
-
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
|
|
125
|
+
// Deposits for non-builders stay in the pending queue. If there is a valid pending
|
|
126
|
+
// deposit for a new validator with this pubkey, keep this deposit pending so the validator
|
|
127
|
+
// can pick it up later.
|
|
128
|
+
if (!isBuilderWithdrawalCredential(deposit.withdrawalCredentials)) {
|
|
129
|
+
pendingDeposits.push(deposit);
|
|
130
|
+
pendingDepositsLookup.add(deposit, pubkeyHex);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (pendingDepositsLookup.hasPendingValidator(state.config, pubkeyHex)) {
|
|
134
|
+
pendingDeposits.push(deposit);
|
|
135
|
+
pendingDepositsLookup.add(deposit, pubkeyHex);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Verify the deposit signature (proof of possession). If invalid the deposit is silently
|
|
140
|
+
// dropped — stake is forfeited, matching the validator deposit contract behavior.
|
|
141
|
+
if (
|
|
142
|
+
!isValidDepositSignature(
|
|
143
|
+
state.config,
|
|
144
|
+
deposit.pubkey,
|
|
145
|
+
deposit.withdrawalCredentials,
|
|
146
|
+
deposit.amount,
|
|
147
|
+
deposit.signature
|
|
148
|
+
)
|
|
149
|
+
) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
addBuilderToRegistry(
|
|
136
154
|
state,
|
|
137
155
|
deposit.pubkey,
|
|
138
|
-
|
|
156
|
+
PAYLOAD_BUILDER_VERSION,
|
|
157
|
+
deposit.withdrawalCredentials.subarray(12),
|
|
139
158
|
deposit.amount,
|
|
140
|
-
deposit.signature,
|
|
141
159
|
deposit.slot
|
|
142
160
|
);
|
|
143
|
-
|
|
144
|
-
builderPubkeys.add(pubkeyHex);
|
|
145
|
-
}
|
|
161
|
+
builderPubkeys.add(pubkeyHex);
|
|
146
162
|
}
|
|
147
163
|
|
|
148
164
|
state.pendingDeposits = pendingDeposits;
|
|
@@ -831,7 +831,7 @@ export class BeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
831
831
|
/**
|
|
832
832
|
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.5/specs/gloas/validator.md#executionpayload
|
|
833
833
|
*/
|
|
834
|
-
withParentPayloadApplied(executionRequests:
|
|
834
|
+
withParentPayloadApplied(executionRequests: gloas.ExecutionRequests): IBeaconStateViewGloas {
|
|
835
835
|
if (this.config.getForkSeq(this.cachedState.slot) < ForkSeq.gloas) {
|
|
836
836
|
throw new Error("withParentPayloadApplied is not available before Gloas");
|
|
837
837
|
}
|
|
@@ -264,7 +264,7 @@ export interface IBeaconStateViewGloas extends IBeaconStateViewFulu {
|
|
|
264
264
|
* operation selection (e.g. voluntary exits) see the same post-apply state that the block
|
|
265
265
|
* processor will see at import.
|
|
266
266
|
*/
|
|
267
|
-
withParentPayloadApplied(executionRequests:
|
|
267
|
+
withParentPayloadApplied(executionRequests: gloas.ExecutionRequests): IBeaconStateViewGloas;
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
/**
|
|
@@ -905,7 +905,7 @@ export class NativeBeaconStateView implements IBeaconStateViewLatestFork {
|
|
|
905
905
|
return this.binding.getIndicesInPayloadTimelinessCommittee(validatorIndex, slot);
|
|
906
906
|
}
|
|
907
907
|
|
|
908
|
-
withParentPayloadApplied(executionRequests:
|
|
908
|
+
withParentPayloadApplied(executionRequests: gloas.ExecutionRequests): IBeaconStateViewGloas {
|
|
909
909
|
const view = new NativeBeaconStateView(this.binding.withParentPayloadApplied(executionRequests));
|
|
910
910
|
if (!isStatePostGloas(view)) {
|
|
911
911
|
throw new Error("Expected gloas state from withParentPayloadApplied");
|
package/src/util/gloas.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import {PublicKey, Signature, verify} from "@chainsafe/blst";
|
|
2
|
+
import {BeaconConfig} from "@lodestar/config";
|
|
1
3
|
import {
|
|
2
4
|
BUILDER_INDEX_FLAG,
|
|
3
5
|
BUILDER_PAYMENT_THRESHOLD_DENOMINATOR,
|
|
4
6
|
BUILDER_PAYMENT_THRESHOLD_NUMERATOR,
|
|
5
7
|
BUILDER_WITHDRAWAL_PREFIX,
|
|
8
|
+
DOMAIN_BUILDER_DEPOSIT,
|
|
6
9
|
EFFECTIVE_BALANCE_INCREMENT,
|
|
7
10
|
FAR_FUTURE_EPOCH,
|
|
8
11
|
MIN_DEPOSIT_AMOUNT,
|
|
@@ -10,15 +13,18 @@ import {
|
|
|
10
13
|
PTC_SIZE,
|
|
11
14
|
SLOTS_PER_EPOCH,
|
|
12
15
|
} from "@lodestar/params";
|
|
13
|
-
import {BuilderIndex, Epoch, ValidatorIndex, gloas} from "@lodestar/types";
|
|
16
|
+
import {BuilderIndex, Epoch, ValidatorIndex, gloas, ssz} from "@lodestar/types";
|
|
14
17
|
import {AttestationData} from "@lodestar/types/phase0";
|
|
15
18
|
import {byteArrayEquals} from "@lodestar/utils";
|
|
19
|
+
import {ZERO_HASH} from "../constants/index.js";
|
|
16
20
|
import {CachedBeaconStateFulu, CachedBeaconStateGloas} from "../types.js";
|
|
17
21
|
import {getBlockRootAtSlot} from "./blockRoot.js";
|
|
22
|
+
import {computeDomain} from "./domain.js";
|
|
18
23
|
import {computeEpochAtSlot} from "./epoch.js";
|
|
19
24
|
import {computeEpochShuffling} from "./epochShuffling.js";
|
|
20
25
|
import {RootCache} from "./rootCache.js";
|
|
21
26
|
import {computePayloadTimelinessCommitteesForEpoch} from "./seed.js";
|
|
27
|
+
import {computeSigningRoot} from "./signingRoot.js";
|
|
22
28
|
import {getActiveValidatorIndices} from "./validator.js";
|
|
23
29
|
|
|
24
30
|
export function isBuilderWithdrawalCredential(withdrawalCredentials: Uint8Array): boolean {
|
|
@@ -241,3 +247,72 @@ export function getPtcWindowEpochCacheData(state: CachedBeaconStateGloas): {
|
|
|
241
247
|
nextPayloadTimelinessCommittees: toUint32Arrays(nextPtcWindow),
|
|
242
248
|
};
|
|
243
249
|
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Add a new builder to the builders registry. Reuses slots from exited and fully withdrawn
|
|
253
|
+
* builders when available, otherwise appends.
|
|
254
|
+
*
|
|
255
|
+
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.11/specs/gloas/beacon-chain.md#new-add_builder_to_registry
|
|
256
|
+
*/
|
|
257
|
+
export function addBuilderToRegistry(
|
|
258
|
+
state: CachedBeaconStateGloas,
|
|
259
|
+
pubkey: Uint8Array,
|
|
260
|
+
version: number,
|
|
261
|
+
executionAddress: Uint8Array,
|
|
262
|
+
amount: number,
|
|
263
|
+
slot: number
|
|
264
|
+
): void {
|
|
265
|
+
const currentEpoch = computeEpochAtSlot(state.slot);
|
|
266
|
+
const depositEpoch = computeEpochAtSlot(slot);
|
|
267
|
+
|
|
268
|
+
let builderIndex = state.builders.length;
|
|
269
|
+
for (let i = 0; i < state.builders.length; i++) {
|
|
270
|
+
const builder = state.builders.getReadonly(i);
|
|
271
|
+
if (builder.withdrawableEpoch <= currentEpoch && builder.balance === 0) {
|
|
272
|
+
builderIndex = i;
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const newBuilder = ssz.gloas.Builder.toViewDU({
|
|
278
|
+
pubkey,
|
|
279
|
+
version,
|
|
280
|
+
executionAddress,
|
|
281
|
+
balance: amount,
|
|
282
|
+
depositEpoch,
|
|
283
|
+
withdrawableEpoch: FAR_FUTURE_EPOCH,
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
if (builderIndex < state.builders.length) {
|
|
287
|
+
state.builders.set(builderIndex, newBuilder);
|
|
288
|
+
} else {
|
|
289
|
+
state.builders.push(newBuilder);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Verify the proof of possession on a builder deposit request.
|
|
295
|
+
*
|
|
296
|
+
* The dedicated `DOMAIN_BUILDER_DEPOSIT` (vs the validator `DOMAIN_DEPOSIT`) prevents replay
|
|
297
|
+
* of validator deposit signatures against the builder deposit contract and vice versa.
|
|
298
|
+
*
|
|
299
|
+
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.11/specs/gloas/beacon-chain.md#new-is_valid_builder_deposit_signature
|
|
300
|
+
*/
|
|
301
|
+
export function isValidBuilderDepositSignature(
|
|
302
|
+
config: BeaconConfig,
|
|
303
|
+
pubkey: Uint8Array,
|
|
304
|
+
withdrawalCredentials: Uint8Array,
|
|
305
|
+
amount: number,
|
|
306
|
+
signature: Uint8Array
|
|
307
|
+
): boolean {
|
|
308
|
+
const depositMessage = {pubkey, withdrawalCredentials, amount};
|
|
309
|
+
const domain = computeDomain(DOMAIN_BUILDER_DEPOSIT, config.GENESIS_FORK_VERSION, ZERO_HASH);
|
|
310
|
+
const signingRoot = computeSigningRoot(ssz.phase0.DepositMessage, depositMessage, domain);
|
|
311
|
+
try {
|
|
312
|
+
const publicKey = PublicKey.fromBytes(pubkey, true);
|
|
313
|
+
const sig = Signature.fromBytes(signature, true);
|
|
314
|
+
return verify(signingRoot, publicKey, sig);
|
|
315
|
+
} catch (_e) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
}
|