@lodestar/state-transition 1.39.0 → 1.40.0-dev.313caaeef7
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 +1 -0
- package/lib/block/index.d.ts.map +1 -1
- package/lib/block/index.js +1 -0
- package/lib/block/index.js.map +1 -1
- package/lib/block/isValidIndexedAttestation.d.ts +4 -5
- package/lib/block/isValidIndexedAttestation.d.ts.map +1 -1
- package/lib/block/isValidIndexedAttestation.js +9 -10
- package/lib/block/isValidIndexedAttestation.js.map +1 -1
- package/lib/block/processAttestationPhase0.d.ts.map +1 -1
- package/lib/block/processAttestationPhase0.js +1 -1
- package/lib/block/processAttestationPhase0.js.map +1 -1
- package/lib/block/processAttesterSlashing.d.ts +3 -2
- package/lib/block/processAttesterSlashing.d.ts.map +1 -1
- package/lib/block/processAttesterSlashing.js +3 -3
- package/lib/block/processAttesterSlashing.js.map +1 -1
- package/lib/block/processBlsToExecutionChange.d.ts +3 -1
- package/lib/block/processBlsToExecutionChange.d.ts.map +1 -1
- package/lib/block/processBlsToExecutionChange.js +7 -11
- package/lib/block/processBlsToExecutionChange.js.map +1 -1
- package/lib/block/processDepositRequest.d.ts +8 -2
- package/lib/block/processDepositRequest.d.ts.map +1 -1
- package/lib/block/processDepositRequest.js +81 -8
- package/lib/block/processDepositRequest.js.map +1 -1
- package/lib/block/processExecutionPayloadBid.d.ts.map +1 -1
- package/lib/block/processExecutionPayloadBid.js +14 -27
- package/lib/block/processExecutionPayloadBid.js.map +1 -1
- package/lib/block/processExecutionPayloadEnvelope.d.ts.map +1 -1
- package/lib/block/processExecutionPayloadEnvelope.js +25 -24
- package/lib/block/processExecutionPayloadEnvelope.js.map +1 -1
- package/lib/block/processOperations.js +1 -1
- package/lib/block/processOperations.js.map +1 -1
- package/lib/block/processProposerSlashing.d.ts +5 -2
- package/lib/block/processProposerSlashing.d.ts.map +1 -1
- package/lib/block/processProposerSlashing.js +7 -5
- 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 +44 -2
- package/lib/block/processVoluntaryExit.js.map +1 -1
- package/lib/block/processWithdrawals.d.ts +1 -0
- package/lib/block/processWithdrawals.d.ts.map +1 -1
- package/lib/block/processWithdrawals.js +121 -66
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/cache/epochCache.d.ts +8 -28
- package/lib/cache/epochCache.d.ts.map +1 -1
- package/lib/cache/epochCache.js +40 -180
- package/lib/cache/epochCache.js.map +1 -1
- package/lib/cache/epochTransitionCache.d.ts +5 -12
- package/lib/cache/epochTransitionCache.d.ts.map +1 -1
- package/lib/cache/epochTransitionCache.js +4 -14
- package/lib/cache/epochTransitionCache.js.map +1 -1
- package/lib/cache/stateCache.d.ts.map +1 -1
- package/lib/cache/stateCache.js +1 -2
- package/lib/cache/stateCache.js.map +1 -1
- package/lib/epoch/processBuilderPendingPayments.d.ts.map +1 -1
- package/lib/epoch/processBuilderPendingPayments.js +1 -4
- package/lib/epoch/processBuilderPendingPayments.js.map +1 -1
- package/lib/epoch/processProposerLookahead.d.ts.map +1 -1
- package/lib/epoch/processProposerLookahead.js +3 -6
- package/lib/epoch/processProposerLookahead.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/rewards/blockRewards.d.ts +2 -1
- package/lib/rewards/blockRewards.d.ts.map +1 -1
- package/lib/rewards/blockRewards.js +3 -2
- package/lib/rewards/blockRewards.js.map +1 -1
- package/lib/rewards/syncCommitteeRewards.d.ts.map +1 -1
- package/lib/rewards/syncCommitteeRewards.js +10 -11
- package/lib/rewards/syncCommitteeRewards.js.map +1 -1
- package/lib/signatureSets/blsToExecutionChange.d.ts +1 -2
- package/lib/signatureSets/blsToExecutionChange.d.ts.map +1 -1
- package/lib/signatureSets/blsToExecutionChange.js +2 -2
- package/lib/signatureSets/blsToExecutionChange.js.map +1 -1
- package/lib/types.d.ts +1 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/util/electra.d.ts.map +1 -1
- package/lib/util/electra.js +1 -2
- package/lib/util/electra.js.map +1 -1
- package/lib/util/epochShuffling.d.ts +1 -34
- package/lib/util/epochShuffling.d.ts.map +1 -1
- package/lib/util/epochShuffling.js +1 -1
- package/lib/util/epochShuffling.js.map +1 -1
- package/lib/util/gloas.d.ts +43 -3
- package/lib/util/gloas.d.ts.map +1 -1
- package/lib/util/gloas.js +93 -5
- package/lib/util/gloas.js.map +1 -1
- package/lib/util/index.d.ts +1 -2
- package/lib/util/index.d.ts.map +1 -1
- package/lib/util/index.js +1 -2
- package/lib/util/index.js.map +1 -1
- package/lib/util/shuffling.d.ts +58 -0
- package/lib/util/shuffling.d.ts.map +1 -0
- package/lib/util/shuffling.js +175 -0
- package/lib/util/shuffling.js.map +1 -0
- package/lib/util/validator.d.ts +5 -0
- package/lib/util/validator.d.ts.map +1 -1
- package/lib/util/validator.js +25 -2
- package/lib/util/validator.js.map +1 -1
- package/package.json +7 -7
- package/src/block/index.ts +1 -0
- package/src/block/isValidIndexedAttestation.ts +17 -12
- package/src/block/processAttestationPhase0.ts +2 -1
- package/src/block/processAttesterSlashing.ts +16 -4
- package/src/block/processBlsToExecutionChange.ts +13 -14
- package/src/block/processDepositRequest.ts +101 -8
- package/src/block/processExecutionPayloadBid.ts +18 -40
- package/src/block/processExecutionPayloadEnvelope.ts +33 -29
- package/src/block/processOperations.ts +1 -1
- package/src/block/processProposerSlashing.ts +21 -11
- package/src/block/processVoluntaryExit.ts +59 -4
- package/src/block/processWithdrawals.ts +168 -70
- package/src/cache/epochCache.ts +52 -214
- package/src/cache/epochTransitionCache.ts +9 -34
- package/src/cache/stateCache.ts +1 -2
- package/src/epoch/processBuilderPendingPayments.ts +1 -5
- package/src/epoch/processProposerLookahead.ts +3 -7
- package/src/index.ts +0 -2
- package/src/rewards/blockRewards.ts +6 -3
- package/src/rewards/syncCommitteeRewards.ts +10 -13
- package/src/signatureSets/blsToExecutionChange.ts +2 -3
- package/src/types.ts +1 -0
- package/src/util/electra.ts +1 -4
- package/src/util/epochShuffling.ts +2 -43
- package/src/util/gloas.ts +109 -8
- package/src/util/index.ts +1 -2
- package/src/util/shuffling.ts +234 -0
- package/src/util/validator.ts +31 -1
- package/lib/util/calculateCommitteeAssignments.d.ts +0 -12
- package/lib/util/calculateCommitteeAssignments.d.ts.map +0 -1
- package/lib/util/calculateCommitteeAssignments.js +0 -26
- package/lib/util/calculateCommitteeAssignments.js.map +0 -1
- package/lib/util/shufflingDecisionRoot.d.ts +0 -20
- package/lib/util/shufflingDecisionRoot.d.ts.map +0 -1
- package/lib/util/shufflingDecisionRoot.js +0 -76
- package/lib/util/shufflingDecisionRoot.js.map +0 -1
- package/src/util/calculateCommitteeAssignments.ts +0 -43
- package/src/util/shufflingDecisionRoot.ts +0 -81
|
@@ -2,22 +2,29 @@ import {byteArrayEquals} from "@chainsafe/ssz";
|
|
|
2
2
|
import {
|
|
3
3
|
FAR_FUTURE_EPOCH,
|
|
4
4
|
ForkSeq,
|
|
5
|
+
MAX_BUILDERS_PER_WITHDRAWALS_SWEEP,
|
|
5
6
|
MAX_EFFECTIVE_BALANCE,
|
|
6
7
|
MAX_PENDING_PARTIALS_PER_WITHDRAWALS_SWEEP,
|
|
7
8
|
MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP,
|
|
8
9
|
MAX_WITHDRAWALS_PER_PAYLOAD,
|
|
9
10
|
MIN_ACTIVATION_BALANCE,
|
|
10
11
|
} from "@lodestar/params";
|
|
11
|
-
import {ValidatorIndex, capella, ssz} from "@lodestar/types";
|
|
12
|
+
import {BuilderIndex, ValidatorIndex, capella, ssz} from "@lodestar/types";
|
|
12
13
|
import {toRootHex} from "@lodestar/utils";
|
|
13
14
|
import {CachedBeaconStateCapella, CachedBeaconStateElectra, CachedBeaconStateGloas} from "../types.js";
|
|
14
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
convertBuilderIndexToValidatorIndex,
|
|
17
|
+
convertValidatorIndexToBuilderIndex,
|
|
18
|
+
isBuilderIndex,
|
|
19
|
+
isParentBlockFull,
|
|
20
|
+
} from "../util/gloas.ts";
|
|
15
21
|
import {
|
|
16
22
|
decreaseBalance,
|
|
17
23
|
getMaxEffectiveBalance,
|
|
18
24
|
hasEth1WithdrawalCredential,
|
|
19
25
|
hasExecutionWithdrawalCredential,
|
|
20
26
|
isCapellaPayloadHeader,
|
|
27
|
+
isPartiallyWithdrawableValidator,
|
|
21
28
|
} from "../util/index.js";
|
|
22
29
|
|
|
23
30
|
export function processWithdrawals(
|
|
@@ -32,9 +39,14 @@ export function processWithdrawals(
|
|
|
32
39
|
|
|
33
40
|
// processedBuilderWithdrawalsCount is withdrawals coming from builder payment since gloas (EIP-7732)
|
|
34
41
|
// processedPartialWithdrawalsCount is withdrawals coming from EL since electra (EIP-7002)
|
|
42
|
+
// processedBuildersSweepCount is withdrawals from builder sweep since gloas (EIP-7732)
|
|
35
43
|
// processedValidatorSweepCount is withdrawals coming from validator sweep
|
|
36
|
-
const {
|
|
37
|
-
|
|
44
|
+
const {
|
|
45
|
+
expectedWithdrawals,
|
|
46
|
+
processedBuilderWithdrawalsCount,
|
|
47
|
+
processedPartialWithdrawalsCount,
|
|
48
|
+
processedBuildersSweepCount,
|
|
49
|
+
} = getExpectedWithdrawals(fork, state);
|
|
38
50
|
const numWithdrawals = expectedWithdrawals.length;
|
|
39
51
|
|
|
40
52
|
// After gloas, withdrawals are verified later in processExecutionPayloadEnvelope
|
|
@@ -78,20 +90,20 @@ export function processWithdrawals(
|
|
|
78
90
|
|
|
79
91
|
if (fork >= ForkSeq.gloas) {
|
|
80
92
|
const stateGloas = state as CachedBeaconStateGloas;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
stateGloas.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
|
|
94
|
+
// Store expected withdrawals for verification
|
|
95
|
+
stateGloas.payloadExpectedWithdrawals = ssz.capella.Withdrawals.toViewDU(expectedWithdrawals);
|
|
96
|
+
|
|
97
|
+
// Update builder pending withdrawals queue
|
|
98
|
+
stateGloas.builderPendingWithdrawals = stateGloas.builderPendingWithdrawals.sliceFrom(
|
|
99
|
+
processedBuilderWithdrawalsCount
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Update next builder index for sweep
|
|
103
|
+
if (stateGloas.builders.length > 0) {
|
|
104
|
+
const nextIndex = stateGloas.nextWithdrawalBuilderIndex + processedBuildersSweepCount;
|
|
105
|
+
stateGloas.nextWithdrawalBuilderIndex = nextIndex % stateGloas.builders.length;
|
|
106
|
+
}
|
|
95
107
|
}
|
|
96
108
|
// Update the nextWithdrawalIndex
|
|
97
109
|
// https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.0/specs/capella/beacon-chain.md#new-update_next_withdrawal_index
|
|
@@ -116,10 +128,14 @@ export function processWithdrawals(
|
|
|
116
128
|
function getBuilderWithdrawals(
|
|
117
129
|
state: CachedBeaconStateGloas,
|
|
118
130
|
withdrawalIndex: number,
|
|
119
|
-
|
|
131
|
+
priorWithdrawals: capella.Withdrawal[],
|
|
132
|
+
builderBalanceAfterWithdrawals: Map<number, number>
|
|
120
133
|
): {builderWithdrawals: capella.Withdrawal[]; withdrawalIndex: number; processedCount: number} {
|
|
134
|
+
const withdrawalsLimit = MAX_WITHDRAWALS_PER_PAYLOAD - 1;
|
|
135
|
+
if (priorWithdrawals.length > withdrawalsLimit) {
|
|
136
|
+
throw Error(`Prior withdrawals exceed limit: ${priorWithdrawals.length} > ${withdrawalsLimit}`);
|
|
137
|
+
}
|
|
121
138
|
const builderWithdrawals: capella.Withdrawal[] = [];
|
|
122
|
-
const epoch = state.epochCtx.epoch;
|
|
123
139
|
const allBuilderPendingWithdrawals =
|
|
124
140
|
state.builderPendingWithdrawals.length <= MAX_WITHDRAWALS_PER_PAYLOAD
|
|
125
141
|
? state.builderPendingWithdrawals.getAllReadonly()
|
|
@@ -127,55 +143,103 @@ function getBuilderWithdrawals(
|
|
|
127
143
|
|
|
128
144
|
let processedCount = 0;
|
|
129
145
|
for (let i = 0; i < state.builderPendingWithdrawals.length; i++) {
|
|
146
|
+
// Check combined length against limit
|
|
147
|
+
const allWithdrawals = priorWithdrawals.length + builderWithdrawals.length;
|
|
148
|
+
if (allWithdrawals >= withdrawalsLimit) {
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
|
|
130
152
|
const withdrawal = allBuilderPendingWithdrawals
|
|
131
153
|
? allBuilderPendingWithdrawals[i]
|
|
132
154
|
: state.builderPendingWithdrawals.getReadonly(i);
|
|
133
155
|
|
|
134
|
-
|
|
135
|
-
|
|
156
|
+
const builderIndex = withdrawal.builderIndex;
|
|
157
|
+
|
|
158
|
+
// Get builder balance (from builder.balance, not state.balances)
|
|
159
|
+
let balance = builderBalanceAfterWithdrawals.get(builderIndex);
|
|
160
|
+
if (balance === undefined) {
|
|
161
|
+
balance = state.builders.getReadonly(builderIndex).balance;
|
|
162
|
+
builderBalanceAfterWithdrawals.set(builderIndex, balance);
|
|
136
163
|
}
|
|
137
164
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
165
|
+
// Use the withdrawal amount directly as specified in the spec
|
|
166
|
+
builderWithdrawals.push({
|
|
167
|
+
index: withdrawalIndex,
|
|
168
|
+
validatorIndex: convertBuilderIndexToValidatorIndex(builderIndex),
|
|
169
|
+
address: withdrawal.feeRecipient,
|
|
170
|
+
amount: BigInt(withdrawal.amount),
|
|
171
|
+
});
|
|
172
|
+
withdrawalIndex++;
|
|
173
|
+
builderBalanceAfterWithdrawals.set(builderIndex, balance - withdrawal.amount);
|
|
141
174
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
balance = state.balances.get(builderIndex);
|
|
145
|
-
balanceAfterWithdrawals.set(builderIndex, balance);
|
|
146
|
-
}
|
|
175
|
+
processedCount++;
|
|
176
|
+
}
|
|
147
177
|
|
|
148
|
-
|
|
178
|
+
return {builderWithdrawals, withdrawalIndex, processedCount};
|
|
179
|
+
}
|
|
149
180
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
181
|
+
function getBuildersSweepWithdrawals(
|
|
182
|
+
state: CachedBeaconStateGloas,
|
|
183
|
+
withdrawalIndex: number,
|
|
184
|
+
numPriorWithdrawal: number,
|
|
185
|
+
builderBalanceAfterWithdrawals: Map<number, number>
|
|
186
|
+
): {buildersSweepWithdrawals: capella.Withdrawal[]; withdrawalIndex: number; processedCount: number} {
|
|
187
|
+
const withdrawalsLimit = MAX_WITHDRAWALS_PER_PAYLOAD - 1;
|
|
188
|
+
if (numPriorWithdrawal > withdrawalsLimit) {
|
|
189
|
+
throw Error(`Prior withdrawals exceed limit: ${numPriorWithdrawal} > ${withdrawalsLimit}`);
|
|
190
|
+
}
|
|
191
|
+
const buildersSweepWithdrawals: capella.Withdrawal[] = [];
|
|
192
|
+
const epoch = state.epochCtx.epoch;
|
|
193
|
+
const builders = state.builders;
|
|
156
194
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
195
|
+
// Return early if no builders
|
|
196
|
+
if (builders.length === 0) {
|
|
197
|
+
return {buildersSweepWithdrawals, withdrawalIndex, processedCount: 0};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const buildersLimit = Math.min(builders.length, MAX_BUILDERS_PER_WITHDRAWALS_SWEEP);
|
|
201
|
+
let processedCount = 0;
|
|
202
|
+
|
|
203
|
+
for (let n = 0; n < buildersLimit; n++) {
|
|
204
|
+
if (buildersSweepWithdrawals.length + numPriorWithdrawal >= withdrawalsLimit) {
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Get next builder in turn
|
|
209
|
+
const builderIndex = (state.nextWithdrawalBuilderIndex + n) % builders.length;
|
|
210
|
+
const builder = builders.getReadonly(builderIndex);
|
|
211
|
+
|
|
212
|
+
// Get builder balance
|
|
213
|
+
let balance = builderBalanceAfterWithdrawals.get(builderIndex);
|
|
214
|
+
if (balance === undefined) {
|
|
215
|
+
balance = builder.balance;
|
|
216
|
+
builderBalanceAfterWithdrawals.set(builderIndex, balance);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Check if builder is withdrawable and has balance
|
|
220
|
+
if (builder.withdrawableEpoch <= epoch && balance > 0) {
|
|
221
|
+
// Withdraw full balance to builder's execution address
|
|
222
|
+
buildersSweepWithdrawals.push({
|
|
223
|
+
index: withdrawalIndex,
|
|
224
|
+
validatorIndex: convertBuilderIndexToValidatorIndex(builderIndex),
|
|
225
|
+
address: builder.executionAddress,
|
|
226
|
+
amount: BigInt(balance),
|
|
227
|
+
});
|
|
228
|
+
withdrawalIndex++;
|
|
229
|
+
builderBalanceAfterWithdrawals.set(builderIndex, 0);
|
|
167
230
|
}
|
|
231
|
+
|
|
168
232
|
processedCount++;
|
|
169
233
|
}
|
|
170
234
|
|
|
171
|
-
return {
|
|
235
|
+
return {buildersSweepWithdrawals, withdrawalIndex, processedCount};
|
|
172
236
|
}
|
|
173
237
|
|
|
174
238
|
function getPendingPartialWithdrawals(
|
|
175
239
|
state: CachedBeaconStateElectra,
|
|
176
240
|
withdrawalIndex: number,
|
|
177
241
|
numPriorWithdrawal: number,
|
|
178
|
-
|
|
242
|
+
validatorBalanceAfterWithdrawals: Map<ValidatorIndex, number>
|
|
179
243
|
): {pendingPartialWithdrawals: capella.Withdrawal[]; withdrawalIndex: number; processedCount: number} {
|
|
180
244
|
const epoch = state.epochCtx.epoch;
|
|
181
245
|
const pendingPartialWithdrawals: capella.Withdrawal[] = [];
|
|
@@ -203,17 +267,17 @@ function getPendingPartialWithdrawals(
|
|
|
203
267
|
: state.pendingPartialWithdrawals.getReadonly(i);
|
|
204
268
|
if (
|
|
205
269
|
withdrawal.withdrawableEpoch > epoch ||
|
|
206
|
-
pendingPartialWithdrawals.length + numPriorWithdrawal
|
|
270
|
+
pendingPartialWithdrawals.length + numPriorWithdrawal >= partialWithdrawalBound
|
|
207
271
|
) {
|
|
208
272
|
break;
|
|
209
273
|
}
|
|
210
274
|
|
|
211
275
|
const validatorIndex = withdrawal.validatorIndex;
|
|
212
276
|
const validator = validators.getReadonly(validatorIndex);
|
|
213
|
-
let balance =
|
|
277
|
+
let balance = validatorBalanceAfterWithdrawals.get(validatorIndex);
|
|
214
278
|
if (balance === undefined) {
|
|
215
279
|
balance = state.balances.get(validatorIndex);
|
|
216
|
-
|
|
280
|
+
validatorBalanceAfterWithdrawals.set(validatorIndex, balance);
|
|
217
281
|
}
|
|
218
282
|
|
|
219
283
|
if (
|
|
@@ -231,7 +295,7 @@ function getPendingPartialWithdrawals(
|
|
|
231
295
|
amount: withdrawableBalance,
|
|
232
296
|
});
|
|
233
297
|
withdrawalIndex++;
|
|
234
|
-
|
|
298
|
+
validatorBalanceAfterWithdrawals.set(validatorIndex, balance - Number(withdrawableBalance));
|
|
235
299
|
}
|
|
236
300
|
processedCount++;
|
|
237
301
|
}
|
|
@@ -244,7 +308,7 @@ function getValidatorsSweepWithdrawals(
|
|
|
244
308
|
state: CachedBeaconStateCapella | CachedBeaconStateElectra | CachedBeaconStateGloas,
|
|
245
309
|
withdrawalIndex: number,
|
|
246
310
|
numPriorWithdrawal: number,
|
|
247
|
-
|
|
311
|
+
validatorBalanceAfterWithdrawals: Map<ValidatorIndex, number>
|
|
248
312
|
): {sweepWithdrawals: capella.Withdrawal[]; processedCount: number} {
|
|
249
313
|
const sweepWithdrawals: capella.Withdrawal[] = [];
|
|
250
314
|
const epoch = state.epochCtx.epoch;
|
|
@@ -264,13 +328,13 @@ function getValidatorsSweepWithdrawals(
|
|
|
264
328
|
const validatorIndex = (nextWithdrawalValidatorIndex + n) % validators.length;
|
|
265
329
|
|
|
266
330
|
const validator = validators.getReadonly(validatorIndex);
|
|
267
|
-
let balance =
|
|
331
|
+
let balance = validatorBalanceAfterWithdrawals.get(validatorIndex);
|
|
268
332
|
if (balance === undefined) {
|
|
269
333
|
balance = balances.get(validatorIndex);
|
|
270
|
-
|
|
334
|
+
validatorBalanceAfterWithdrawals.set(validatorIndex, balance);
|
|
271
335
|
}
|
|
272
336
|
|
|
273
|
-
const {withdrawableEpoch, withdrawalCredentials
|
|
337
|
+
const {withdrawableEpoch, withdrawalCredentials} = validator;
|
|
274
338
|
const hasWithdrawableCredentials = isPostElectra
|
|
275
339
|
? hasExecutionWithdrawalCredential(withdrawalCredentials)
|
|
276
340
|
: hasEth1WithdrawalCredential(withdrawalCredentials);
|
|
@@ -290,13 +354,11 @@ function getValidatorsSweepWithdrawals(
|
|
|
290
354
|
amount: BigInt(balance),
|
|
291
355
|
});
|
|
292
356
|
withdrawalIndex++;
|
|
293
|
-
|
|
294
|
-
} else if (
|
|
295
|
-
effectiveBalance === (isPostElectra ? getMaxEffectiveBalance(withdrawalCredentials) : MAX_EFFECTIVE_BALANCE) &&
|
|
296
|
-
balance > effectiveBalance
|
|
297
|
-
) {
|
|
357
|
+
validatorBalanceAfterWithdrawals.set(validatorIndex, 0);
|
|
358
|
+
} else if (isPartiallyWithdrawableValidator(fork, validator, balance)) {
|
|
298
359
|
// capella partial withdrawal
|
|
299
|
-
const
|
|
360
|
+
const maxEffectiveBalance = isPostElectra ? getMaxEffectiveBalance(withdrawalCredentials) : MAX_EFFECTIVE_BALANCE;
|
|
361
|
+
const partialAmount = balance - maxEffectiveBalance;
|
|
300
362
|
sweepWithdrawals.push({
|
|
301
363
|
index: withdrawalIndex,
|
|
302
364
|
validatorIndex,
|
|
@@ -304,7 +366,7 @@ function getValidatorsSweepWithdrawals(
|
|
|
304
366
|
amount: BigInt(partialAmount),
|
|
305
367
|
});
|
|
306
368
|
withdrawalIndex++;
|
|
307
|
-
|
|
369
|
+
validatorBalanceAfterWithdrawals.set(validatorIndex, balance - partialAmount);
|
|
308
370
|
}
|
|
309
371
|
processedCount++;
|
|
310
372
|
}
|
|
@@ -317,7 +379,16 @@ function applyWithdrawals(
|
|
|
317
379
|
withdrawals: capella.Withdrawal[]
|
|
318
380
|
): void {
|
|
319
381
|
for (const withdrawal of withdrawals) {
|
|
320
|
-
|
|
382
|
+
if (isBuilderIndex(withdrawal.validatorIndex)) {
|
|
383
|
+
// Handle builder withdrawal
|
|
384
|
+
const builderIndex = convertValidatorIndexToBuilderIndex(withdrawal.validatorIndex);
|
|
385
|
+
const builder = (state as CachedBeaconStateGloas).builders.get(builderIndex);
|
|
386
|
+
const withdrawalAmount = Number(withdrawal.amount);
|
|
387
|
+
builder.balance -= Math.min(withdrawalAmount, builder.balance);
|
|
388
|
+
} else {
|
|
389
|
+
// Handle validator withdrawal
|
|
390
|
+
decreaseBalance(state, withdrawal.validatorIndex, Number(withdrawal.amount));
|
|
391
|
+
}
|
|
321
392
|
}
|
|
322
393
|
}
|
|
323
394
|
|
|
@@ -328,6 +399,7 @@ export function getExpectedWithdrawals(
|
|
|
328
399
|
expectedWithdrawals: capella.Withdrawal[];
|
|
329
400
|
processedBuilderWithdrawalsCount: number;
|
|
330
401
|
processedPartialWithdrawalsCount: number;
|
|
402
|
+
processedBuildersSweepCount: number;
|
|
331
403
|
processedValidatorSweepCount: number;
|
|
332
404
|
} {
|
|
333
405
|
if (fork < ForkSeq.capella) {
|
|
@@ -337,20 +409,28 @@ export function getExpectedWithdrawals(
|
|
|
337
409
|
let withdrawalIndex = state.nextWithdrawalIndex;
|
|
338
410
|
|
|
339
411
|
const expectedWithdrawals: capella.Withdrawal[] = [];
|
|
340
|
-
//
|
|
412
|
+
// Separate maps to track balances after applying withdrawals
|
|
341
413
|
// https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.0/specs/capella/beacon-chain.md#new-get_balance_after_withdrawals
|
|
342
|
-
const
|
|
414
|
+
const builderBalanceAfterWithdrawals = new Map<BuilderIndex, number>();
|
|
415
|
+
const validatorBalanceAfterWithdrawals = new Map<ValidatorIndex, number>();
|
|
343
416
|
// partialWithdrawalsCount is withdrawals coming from EL since electra (EIP-7002)
|
|
344
417
|
let processedPartialWithdrawalsCount = 0;
|
|
345
418
|
// builderWithdrawalsCount is withdrawals coming from builder payments since Gloas (EIP-7732)
|
|
346
419
|
let processedBuilderWithdrawalsCount = 0;
|
|
420
|
+
// buildersSweepCount is withdrawals from builder sweep since Gloas (EIP-7732)
|
|
421
|
+
let processedBuildersSweepCount = 0;
|
|
347
422
|
|
|
348
423
|
if (fork >= ForkSeq.gloas) {
|
|
349
424
|
const {
|
|
350
425
|
builderWithdrawals,
|
|
351
426
|
withdrawalIndex: newWithdrawalIndex,
|
|
352
427
|
processedCount,
|
|
353
|
-
} = getBuilderWithdrawals(
|
|
428
|
+
} = getBuilderWithdrawals(
|
|
429
|
+
state as CachedBeaconStateGloas,
|
|
430
|
+
withdrawalIndex,
|
|
431
|
+
expectedWithdrawals,
|
|
432
|
+
builderBalanceAfterWithdrawals
|
|
433
|
+
);
|
|
354
434
|
|
|
355
435
|
expectedWithdrawals.push(...builderWithdrawals);
|
|
356
436
|
withdrawalIndex = newWithdrawalIndex;
|
|
@@ -366,7 +446,7 @@ export function getExpectedWithdrawals(
|
|
|
366
446
|
state as CachedBeaconStateElectra,
|
|
367
447
|
withdrawalIndex,
|
|
368
448
|
expectedWithdrawals.length,
|
|
369
|
-
|
|
449
|
+
validatorBalanceAfterWithdrawals
|
|
370
450
|
);
|
|
371
451
|
|
|
372
452
|
expectedWithdrawals.push(...pendingPartialWithdrawals);
|
|
@@ -374,12 +454,29 @@ export function getExpectedWithdrawals(
|
|
|
374
454
|
processedPartialWithdrawalsCount = processedCount;
|
|
375
455
|
}
|
|
376
456
|
|
|
457
|
+
if (fork >= ForkSeq.gloas) {
|
|
458
|
+
const {
|
|
459
|
+
buildersSweepWithdrawals,
|
|
460
|
+
withdrawalIndex: newWithdrawalIndex,
|
|
461
|
+
processedCount,
|
|
462
|
+
} = getBuildersSweepWithdrawals(
|
|
463
|
+
state as CachedBeaconStateGloas,
|
|
464
|
+
withdrawalIndex,
|
|
465
|
+
expectedWithdrawals.length,
|
|
466
|
+
builderBalanceAfterWithdrawals
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
expectedWithdrawals.push(...buildersSweepWithdrawals);
|
|
470
|
+
withdrawalIndex = newWithdrawalIndex;
|
|
471
|
+
processedBuildersSweepCount = processedCount;
|
|
472
|
+
}
|
|
473
|
+
|
|
377
474
|
const {sweepWithdrawals, processedCount: processedValidatorSweepCount} = getValidatorsSweepWithdrawals(
|
|
378
475
|
fork,
|
|
379
476
|
state,
|
|
380
477
|
withdrawalIndex,
|
|
381
478
|
expectedWithdrawals.length,
|
|
382
|
-
|
|
479
|
+
validatorBalanceAfterWithdrawals
|
|
383
480
|
);
|
|
384
481
|
|
|
385
482
|
expectedWithdrawals.push(...sweepWithdrawals);
|
|
@@ -388,6 +485,7 @@ export function getExpectedWithdrawals(
|
|
|
388
485
|
expectedWithdrawals,
|
|
389
486
|
processedBuilderWithdrawalsCount,
|
|
390
487
|
processedPartialWithdrawalsCount,
|
|
488
|
+
processedBuildersSweepCount,
|
|
391
489
|
processedValidatorSweepCount,
|
|
392
490
|
};
|
|
393
491
|
}
|