@lodestar/state-transition 1.45.0 → 1.46.0-dev.18a1510f34
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.map +1 -1
- package/lib/block/index.js +3 -2
- package/lib/block/index.js.map +1 -1
- package/lib/block/processAttestations.d.ts +2 -2
- package/lib/block/processAttestations.d.ts.map +1 -1
- package/lib/block/processAttestations.js +2 -2
- package/lib/block/processAttestations.js.map +1 -1
- package/lib/block/processAttestationsAltair.d.ts +6 -3
- package/lib/block/processAttestationsAltair.d.ts.map +1 -1
- package/lib/block/processAttestationsAltair.js +13 -8
- package/lib/block/processAttestationsAltair.js.map +1 -1
- package/lib/block/processBuilderDepositRequest.d.ts.map +1 -1
- package/lib/block/processBuilderDepositRequest.js +13 -7
- package/lib/block/processBuilderDepositRequest.js.map +1 -1
- package/lib/block/processExecutionPayloadBid.d.ts +2 -2
- package/lib/block/processExecutionPayloadBid.d.ts.map +1 -1
- package/lib/block/processExecutionPayloadBid.js +2 -0
- package/lib/block/processExecutionPayloadBid.js.map +1 -1
- package/lib/block/processOperations.d.ts +2 -2
- package/lib/block/processOperations.d.ts.map +1 -1
- package/lib/block/processOperations.js +19 -3
- package/lib/block/processOperations.js.map +1 -1
- package/lib/block/processParentExecutionPayload.d.ts.map +1 -1
- package/lib/block/processParentExecutionPayload.js +15 -1
- package/lib/block/processParentExecutionPayload.js.map +1 -1
- package/lib/block/processWithdrawalRequest.d.ts.map +1 -1
- package/lib/block/processWithdrawalRequest.js +2 -2
- package/lib/block/processWithdrawalRequest.js.map +1 -1
- package/lib/block/processWithdrawals.js +1 -1
- package/lib/block/processWithdrawals.js.map +1 -1
- package/lib/cache/epochCache.d.ts.map +1 -1
- package/lib/cache/epochCache.js +18 -19
- package/lib/cache/epochCache.js.map +1 -1
- package/lib/cache/stateCache.d.ts.map +1 -1
- package/lib/cache/stateCache.js +2 -4
- package/lib/cache/stateCache.js.map +1 -1
- package/lib/epoch/processParticipationFlagUpdates.d.ts +2 -2
- package/lib/epoch/processParticipationFlagUpdates.d.ts.map +1 -1
- package/lib/epoch/processParticipationFlagUpdates.js +13 -0
- package/lib/epoch/processParticipationFlagUpdates.js.map +1 -1
- package/lib/epoch/processRewardsAndPenalties.d.ts.map +1 -1
- package/lib/epoch/processRewardsAndPenalties.js +1 -2
- package/lib/epoch/processRewardsAndPenalties.js.map +1 -1
- package/lib/lightClient/proofs.d.ts.map +1 -1
- package/lib/lightClient/proofs.js +28 -2
- package/lib/lightClient/proofs.js.map +1 -1
- package/lib/lightClient/spec/index.d.ts.map +1 -1
- package/lib/lightClient/spec/index.js +7 -4
- package/lib/lightClient/spec/index.js.map +1 -1
- package/lib/lightClient/spec/processLightClientUpdate.d.ts.map +1 -1
- package/lib/lightClient/spec/processLightClientUpdate.js +8 -2
- package/lib/lightClient/spec/processLightClientUpdate.js.map +1 -1
- package/lib/lightClient/spec/utils.d.ts +7 -2
- package/lib/lightClient/spec/utils.d.ts.map +1 -1
- package/lib/lightClient/spec/utils.js +130 -19
- package/lib/lightClient/spec/utils.js.map +1 -1
- package/lib/lightClient/spec/validateLightClientBootstrap.d.ts.map +1 -1
- package/lib/lightClient/spec/validateLightClientBootstrap.js +2 -7
- package/lib/lightClient/spec/validateLightClientBootstrap.js.map +1 -1
- package/lib/lightClient/spec/validateLightClientUpdate.d.ts.map +1 -1
- package/lib/lightClient/spec/validateLightClientUpdate.js +6 -5
- package/lib/lightClient/spec/validateLightClientUpdate.js.map +1 -1
- package/lib/lightClient/types.d.ts +3 -1
- package/lib/lightClient/types.d.ts.map +1 -1
- package/lib/metrics.js +2 -4
- package/lib/metrics.js.map +1 -1
- package/lib/rewards/blockRewards.d.ts.map +1 -1
- package/lib/rewards/blockRewards.js +7 -4
- package/lib/rewards/blockRewards.js.map +1 -1
- package/lib/slot/upgradeStateToAltair.js +1 -1
- package/lib/slot/upgradeStateToAltair.js.map +1 -1
- package/lib/slot/upgradeStateToGloas.d.ts.map +1 -1
- package/lib/slot/upgradeStateToGloas.js +49 -10
- package/lib/slot/upgradeStateToGloas.js.map +1 -1
- package/lib/util/clock.d.ts +55 -0
- package/lib/util/clock.d.ts.map +1 -0
- package/lib/util/clock.js +142 -0
- package/lib/util/clock.js.map +1 -0
- package/lib/util/execution.d.ts.map +1 -1
- package/lib/util/execution.js +7 -2
- package/lib/util/execution.js.map +1 -1
- package/lib/util/gloas.d.ts +5 -2
- package/lib/util/gloas.d.ts.map +1 -1
- package/lib/util/gloas.js +15 -15
- package/lib/util/gloas.js.map +1 -1
- package/lib/util/index.d.ts +2 -0
- package/lib/util/index.d.ts.map +1 -1
- package/lib/util/index.js +2 -0
- package/lib/util/index.js.map +1 -1
- package/lib/util/ssz.d.ts +9 -0
- package/lib/util/ssz.d.ts.map +1 -0
- package/lib/util/ssz.js +39 -0
- package/lib/util/ssz.js.map +1 -0
- package/package.json +14 -14
- package/src/block/index.ts +4 -3
- package/src/block/processAttestations.ts +10 -2
- package/src/block/processAttestationsAltair.ts +19 -10
- package/src/block/processBuilderDepositRequest.ts +21 -8
- package/src/block/processExecutionPayloadBid.ts +5 -2
- package/src/block/processOperations.ts +31 -3
- package/src/block/processParentExecutionPayload.ts +26 -1
- package/src/block/processWithdrawalRequest.ts +6 -2
- package/src/block/processWithdrawals.ts +1 -1
- package/src/cache/epochCache.ts +19 -22
- package/src/cache/stateCache.ts +2 -4
- package/src/epoch/processParticipationFlagUpdates.ts +20 -2
- package/src/epoch/processRewardsAndPenalties.ts +1 -2
- package/src/lightClient/proofs.ts +36 -1
- package/src/lightClient/spec/index.ts +8 -4
- package/src/lightClient/spec/processLightClientUpdate.ts +13 -1
- package/src/lightClient/spec/utils.ts +200 -30
- package/src/lightClient/spec/validateLightClientBootstrap.ts +3 -10
- package/src/lightClient/spec/validateLightClientUpdate.ts +11 -21
- package/src/lightClient/types.ts +3 -1
- package/src/metrics.ts +2 -4
- package/src/rewards/blockRewards.ts +20 -5
- package/src/slot/upgradeStateToAltair.ts +2 -1
- package/src/slot/upgradeStateToGloas.ts +85 -10
- package/src/util/clock.ts +183 -0
- package/src/util/execution.ts +9 -4
- package/src/util/gloas.ts +18 -19
- package/src/util/index.ts +2 -0
- package/src/util/ssz.ts +42 -0
package/lib/util/ssz.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { BranchNode, LeafNode, zeroNode } from "@chainsafe/persistent-merkle-tree";
|
|
2
|
+
import { progressiveSubtreeFillToContents } from "@chainsafe/ssz";
|
|
3
|
+
// TODO: move these utils to @chainsafe/ssz (progressive.ts, next to progressiveSubtreeFillToContents)
|
|
4
|
+
/** Root node (chunks + length mix-in) of a zero-filled ProgressiveListBasicType of `length` items */
|
|
5
|
+
export function zeroProgressiveListBasicRootNode(itemsPerChunk, length) {
|
|
6
|
+
const chunkCount = Math.ceil(length / itemsPerChunk);
|
|
7
|
+
// mirrors ssz's progressiveSubtreeCount (subtree capacities 1, 4, 16, ...)
|
|
8
|
+
let numSubtrees = 0;
|
|
9
|
+
for (let remaining = chunkCount, subtreeLength = 1; remaining > 0; subtreeLength *= 4) {
|
|
10
|
+
remaining -= Math.min(remaining, subtreeLength);
|
|
11
|
+
numSubtrees++;
|
|
12
|
+
}
|
|
13
|
+
return new BranchNode(zeroProgressiveNode(numSubtrees), LeafNode.fromUint32(length));
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Root node of a progressive list from its chunk/element nodes + length mix-in.
|
|
17
|
+
* `nodes` are packed 32-byte chunk leaves for basic lists, or element root nodes for composite lists.
|
|
18
|
+
*/
|
|
19
|
+
export function progressiveListRootNode(nodes, length) {
|
|
20
|
+
return new BranchNode(progressiveSubtreeFillToContents(nodes), LeafNode.fromUint32(length));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Return the chunks node of a zero-filled progressive merkle list spanning `numSubtrees`
|
|
24
|
+
* balanced subtrees (chunk capacities 1, 4, 16, ... = 4^i; depths 0, 2, 4, ... = 2i).
|
|
25
|
+
*
|
|
26
|
+
* Not memoized: the zero data is already fully shared via the cached zeroNode(2i) subtrees;
|
|
27
|
+
* only the O(numSubtrees) spine BranchNodes (~10 at 2M validators) are allocated per call.
|
|
28
|
+
*/
|
|
29
|
+
function zeroProgressiveNode(numSubtrees) {
|
|
30
|
+
// chain(k) = B(zeroNode(0), B(zeroNode(2), ... B(zeroNode(2(k-1)), zeroNode(0))))
|
|
31
|
+
let node = zeroNode(0); // terminator
|
|
32
|
+
for (let i = numSubtrees - 1; i >= 0; i--) {
|
|
33
|
+
// BranchNode(left: balanced subtree i, right: rest of chain) — chain grows to the right,
|
|
34
|
+
// same as ssz progressiveSubtreeFillToContents: `root = new BranchNode(subtreeRoots[i], root)`
|
|
35
|
+
node = new BranchNode(zeroNode(2 * i), node);
|
|
36
|
+
}
|
|
37
|
+
return node;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=ssz.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssz.js","sourceRoot":"","sources":["../../src/util/ssz.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,QAAQ,EAAQ,QAAQ,EAAC,MAAM,mCAAmC,CAAC;AACvF,OAAO,EAAC,gCAAgC,EAAC,MAAM,gBAAgB,CAAC;AAEhE,sGAAsG;AAEtG,qGAAqG;AACrG,MAAM,UAAU,gCAAgC,CAAC,aAAqB,EAAE,MAAc,EAAQ;IAC5F,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,aAAa,CAAC,CAAC;IACrD,2EAA2E;IAC3E,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,KAAK,IAAI,SAAS,GAAG,UAAU,EAAE,aAAa,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,aAAa,IAAI,CAAC,EAAE,CAAC;QACtF,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAChD,WAAW,EAAE,CAAC;IAChB,CAAC;IACD,OAAO,IAAI,UAAU,CAAC,mBAAmB,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AAAA,CACtF;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAa,EAAE,MAAc,EAAQ;IAC3E,OAAO,IAAI,UAAU,CAAC,gCAAgC,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AAAA,CAC7F;AAED;;;;;;GAMG;AACH,SAAS,mBAAmB,CAAC,WAAmB,EAAQ;IACtD,kFAAkF;IAClF,IAAI,IAAI,GAAS,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa;IAC3C,KAAK,IAAI,CAAC,GAAG,WAAW,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,yFAAyF;QACzF,+FAA+F;QAC/F,IAAI,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACb"}
|
package/package.json
CHANGED
|
@@ -11,36 +11,36 @@
|
|
|
11
11
|
"bugs": {
|
|
12
12
|
"url": "https://github.com/ChainSafe/lodestar/issues"
|
|
13
13
|
},
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.46.0-dev.18a1510f34",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
18
|
-
"
|
|
18
|
+
"typescript": "./src/index.ts",
|
|
19
19
|
"types": "./lib/index.d.ts",
|
|
20
20
|
"import": "./lib/index.js"
|
|
21
21
|
},
|
|
22
22
|
"./block": {
|
|
23
|
-
"
|
|
23
|
+
"typescript": "./src/block/index.ts",
|
|
24
24
|
"types": "./lib/block/index.d.ts",
|
|
25
25
|
"import": "./lib/block/index.js"
|
|
26
26
|
},
|
|
27
27
|
"./epoch": {
|
|
28
|
-
"
|
|
28
|
+
"typescript": "./src/epoch/index.ts",
|
|
29
29
|
"types": "./lib/epoch/index.d.ts",
|
|
30
30
|
"import": "./lib/epoch/index.js"
|
|
31
31
|
},
|
|
32
32
|
"./slot": {
|
|
33
|
-
"
|
|
33
|
+
"typescript": "./src/slot/index.ts",
|
|
34
34
|
"types": "./lib/slot/index.d.ts",
|
|
35
35
|
"import": "./lib/slot/index.js"
|
|
36
36
|
},
|
|
37
37
|
"./light-client": {
|
|
38
|
-
"
|
|
38
|
+
"typescript": "./src/lightClient/spec/index.ts",
|
|
39
39
|
"types": "./lib/lightClient/spec/index.d.ts",
|
|
40
40
|
"import": "./lib/lightClient/spec/index.js"
|
|
41
41
|
},
|
|
42
42
|
"./test-utils": {
|
|
43
|
-
"
|
|
43
|
+
"typescript": "./src/testUtils/index.ts",
|
|
44
44
|
"types": "./lib/testUtils/index.d.ts",
|
|
45
45
|
"import": "./lib/testUtils/index.js"
|
|
46
46
|
}
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"lint:fix": "pnpm run lint --write",
|
|
62
62
|
"test": "pnpm test:unit",
|
|
63
63
|
"test:unit": "vitest run --project unit --project unit-minimal",
|
|
64
|
-
"check-readme": "pnpm exec
|
|
64
|
+
"check-readme": "pnpm exec tsx ../../scripts/check_readme.ts"
|
|
65
65
|
},
|
|
66
66
|
"types": "lib/index.d.ts",
|
|
67
67
|
"dependencies": {
|
|
@@ -71,14 +71,14 @@
|
|
|
71
71
|
"@chainsafe/pubkey-index-map": "^3.0.0",
|
|
72
72
|
"@chainsafe/ssz": "^1.6.2",
|
|
73
73
|
"@chainsafe/swap-or-not-shuffle": "^1.2.1",
|
|
74
|
-
"@lodestar/config": "^1.
|
|
75
|
-
"@lodestar/params": "^1.
|
|
76
|
-
"@lodestar/types": "^1.
|
|
77
|
-
"@lodestar/utils": "^1.
|
|
74
|
+
"@lodestar/config": "^1.46.0-dev.18a1510f34",
|
|
75
|
+
"@lodestar/params": "^1.46.0-dev.18a1510f34",
|
|
76
|
+
"@lodestar/types": "^1.46.0-dev.18a1510f34",
|
|
77
|
+
"@lodestar/utils": "^1.46.0-dev.18a1510f34",
|
|
78
78
|
"@vekexasia/bigint-buffer2": "^1.1.1"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@lodestar/api": "^1.
|
|
81
|
+
"@lodestar/api": "^1.46.0-dev.18a1510f34"
|
|
82
82
|
},
|
|
83
83
|
"keywords": [
|
|
84
84
|
"ethereum",
|
|
@@ -86,5 +86,5 @@
|
|
|
86
86
|
"beacon",
|
|
87
87
|
"blockchain"
|
|
88
88
|
],
|
|
89
|
-
"gitHead": "
|
|
89
|
+
"gitHead": "ab4c525506d9452c53bf05563078de14c40d981f"
|
|
90
90
|
}
|
package/src/block/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {ForkPostGloas, ForkSeq} from "@lodestar/params";
|
|
2
|
-
import {BeaconBlock, BlindedBeaconBlock, altair, capella} from "@lodestar/types";
|
|
2
|
+
import {BeaconBlock, BlindedBeaconBlock, Slot, altair, capella} from "@lodestar/types";
|
|
3
3
|
import {BeaconStateTransitionMetrics} from "../metrics.js";
|
|
4
4
|
import {
|
|
5
5
|
CachedBeaconStateAllForks,
|
|
@@ -86,8 +86,9 @@ export function processBlock(
|
|
|
86
86
|
processExecutionPayload(fork, state as CachedBeaconStateBellatrix, block.body, externalData);
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
let parentSlot: Slot | null = null;
|
|
89
90
|
if (fork >= ForkSeq.gloas) {
|
|
90
|
-
processExecutionPayloadBid(
|
|
91
|
+
parentSlot = processExecutionPayloadBid(
|
|
91
92
|
state as CachedBeaconStateGloas,
|
|
92
93
|
(block as BeaconBlock<ForkPostGloas>).body.signedExecutionPayloadBid
|
|
93
94
|
);
|
|
@@ -95,7 +96,7 @@ export function processBlock(
|
|
|
95
96
|
|
|
96
97
|
processRandao(state, block, verifySignatures);
|
|
97
98
|
processEth1Data(state, block.body.eth1Data);
|
|
98
|
-
processOperations(fork, state, block.body, opts, metrics);
|
|
99
|
+
processOperations(fork, state, block.body, parentSlot, opts, metrics);
|
|
99
100
|
if (fork >= ForkSeq.altair) {
|
|
100
101
|
processSyncAggregate(state, block as altair.BeaconBlock, verifySignatures);
|
|
101
102
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {ForkSeq} from "@lodestar/params";
|
|
2
|
-
import {Attestation} from "@lodestar/types";
|
|
2
|
+
import {Attestation, Slot} from "@lodestar/types";
|
|
3
3
|
import {BeaconStateTransitionMetrics} from "../metrics.js";
|
|
4
4
|
import {CachedBeaconStateAllForks, CachedBeaconStateAltair, CachedBeaconStatePhase0} from "../types.js";
|
|
5
5
|
import {processAttestationPhase0} from "./processAttestationPhase0.js";
|
|
@@ -12,6 +12,7 @@ export function processAttestations(
|
|
|
12
12
|
fork: ForkSeq,
|
|
13
13
|
state: CachedBeaconStateAllForks,
|
|
14
14
|
attestations: Attestation[],
|
|
15
|
+
parentSlot: Slot | null,
|
|
15
16
|
verifySignatures = true,
|
|
16
17
|
metrics?: BeaconStateTransitionMetrics | null
|
|
17
18
|
): void {
|
|
@@ -20,6 +21,13 @@ export function processAttestations(
|
|
|
20
21
|
processAttestationPhase0(state as CachedBeaconStatePhase0, attestation, verifySignatures);
|
|
21
22
|
}
|
|
22
23
|
} else {
|
|
23
|
-
processAttestationsAltair(
|
|
24
|
+
processAttestationsAltair(
|
|
25
|
+
fork,
|
|
26
|
+
state as CachedBeaconStateAltair,
|
|
27
|
+
attestations,
|
|
28
|
+
parentSlot,
|
|
29
|
+
verifySignatures,
|
|
30
|
+
metrics
|
|
31
|
+
);
|
|
24
32
|
}
|
|
25
33
|
}
|
|
@@ -14,13 +14,13 @@ import {
|
|
|
14
14
|
TIMELY_TARGET_WEIGHT,
|
|
15
15
|
WEIGHT_DENOMINATOR,
|
|
16
16
|
} from "@lodestar/params";
|
|
17
|
-
import {Attestation, Epoch, phase0} from "@lodestar/types";
|
|
17
|
+
import {Attestation, Epoch, Slot, phase0} from "@lodestar/types";
|
|
18
18
|
import {byteArrayEquals, intSqrt} from "@lodestar/utils";
|
|
19
19
|
import {BeaconStateTransitionMetrics} from "../metrics.js";
|
|
20
20
|
import {getAttestationWithIndicesSignatureSet} from "../signatureSets/indexedAttestation.js";
|
|
21
21
|
import {BeaconStateView} from "../stateView/beaconStateView.js";
|
|
22
22
|
import {CachedBeaconStateAltair, CachedBeaconStateGloas} from "../types.js";
|
|
23
|
-
import {
|
|
23
|
+
import {isAttestationSameSlotRootCache} from "../util/gloas.js";
|
|
24
24
|
import {increaseBalance, verifySignatureSet} from "../util/index.js";
|
|
25
25
|
import {RootCache} from "../util/rootCache.js";
|
|
26
26
|
import {checkpointToStr, isTimelyTarget, validateAttestation} from "./processAttestationPhase0.js";
|
|
@@ -37,6 +37,7 @@ export function processAttestationsAltair(
|
|
|
37
37
|
fork: ForkSeq,
|
|
38
38
|
state: CachedBeaconStateAltair | CachedBeaconStateGloas,
|
|
39
39
|
attestations: Attestation[],
|
|
40
|
+
parentSlot: Slot | null,
|
|
40
41
|
verifySignature = true,
|
|
41
42
|
metrics?: BeaconStateTransitionMetrics | null
|
|
42
43
|
): void {
|
|
@@ -76,13 +77,14 @@ export function processAttestationsAltair(
|
|
|
76
77
|
// Count how much additional weight added to current or previous epoch's builder pending payment (in ETH increment)
|
|
77
78
|
let paymentWeightToAdd = 0;
|
|
78
79
|
|
|
79
|
-
const flagsAttestation = getAttestationParticipationStatus(
|
|
80
|
+
const {flags: flagsAttestation, isSameSlotAttestation} = getAttestationParticipationStatus(
|
|
80
81
|
fork,
|
|
81
82
|
data,
|
|
82
83
|
stateSlot - data.slot,
|
|
83
84
|
epochCtx.epoch,
|
|
84
85
|
rootCache,
|
|
85
|
-
fork >= ForkSeq.gloas ? (state as CachedBeaconStateGloas).executionPayloadAvailability : null
|
|
86
|
+
fork >= ForkSeq.gloas ? (state as CachedBeaconStateGloas).executionPayloadAvailability : null,
|
|
87
|
+
parentSlot
|
|
86
88
|
);
|
|
87
89
|
|
|
88
90
|
// For each participant, update their participation
|
|
@@ -132,7 +134,7 @@ export function processAttestationsAltair(
|
|
|
132
134
|
}
|
|
133
135
|
}
|
|
134
136
|
|
|
135
|
-
if (
|
|
137
|
+
if (isSameSlotAttestation && flagsNewSet !== 0) {
|
|
136
138
|
paymentWeightToAdd += effectiveBalanceIncrements[validatorIndex];
|
|
137
139
|
}
|
|
138
140
|
}
|
|
@@ -179,8 +181,9 @@ export function getAttestationParticipationStatus(
|
|
|
179
181
|
inclusionDelay: number,
|
|
180
182
|
currentEpoch: Epoch,
|
|
181
183
|
rootCache: RootCache,
|
|
182
|
-
executionPayloadAvailability: BitArray | null
|
|
183
|
-
|
|
184
|
+
executionPayloadAvailability: BitArray | null,
|
|
185
|
+
parentSlot: Slot | null
|
|
186
|
+
): {flags: number; isSameSlotAttestation: boolean} {
|
|
184
187
|
const justifiedCheckpoint =
|
|
185
188
|
data.target.epoch === currentEpoch ? rootCache.currentJustifiedCheckpoint : rootCache.previousJustifiedCheckpoint;
|
|
186
189
|
|
|
@@ -206,10 +209,13 @@ export function getAttestationParticipationStatus(
|
|
|
206
209
|
let isMatchingHead =
|
|
207
210
|
isMatchingTarget && byteArrayEquals(data.beaconBlockRoot, rootCache.getBlockRootAtSlot(data.slot));
|
|
208
211
|
|
|
212
|
+
let isSameSlotAttestation = false;
|
|
213
|
+
|
|
209
214
|
if (fork >= ForkSeq.gloas) {
|
|
210
215
|
let isMatchingPayload = false;
|
|
216
|
+
isSameSlotAttestation = isAttestationSameSlotRootCache(rootCache, data);
|
|
211
217
|
|
|
212
|
-
if (
|
|
218
|
+
if (isSameSlotAttestation) {
|
|
213
219
|
if (data.index !== 0) {
|
|
214
220
|
throw new Error("Attesting same slot must indicate empty payload");
|
|
215
221
|
}
|
|
@@ -218,13 +224,16 @@ export function getAttestationParticipationStatus(
|
|
|
218
224
|
if (executionPayloadAvailability === null) {
|
|
219
225
|
throw new Error("Must supply executionPayloadAvailability post-gloas");
|
|
220
226
|
}
|
|
227
|
+
if (parentSlot === null) {
|
|
228
|
+
throw new Error("Must supply parentSlot post-gloas");
|
|
229
|
+
}
|
|
221
230
|
|
|
222
231
|
if (data.index !== 0 && data.index !== 1) {
|
|
223
232
|
throw new Error(`data index must be 0 or 1 index=${data.index}`);
|
|
224
233
|
}
|
|
225
234
|
|
|
226
235
|
isMatchingPayload =
|
|
227
|
-
Boolean(data.index) === executionPayloadAvailability.get(
|
|
236
|
+
Boolean(data.index) === executionPayloadAvailability.get(parentSlot % SLOTS_PER_HISTORICAL_ROOT);
|
|
228
237
|
}
|
|
229
238
|
|
|
230
239
|
isMatchingHead = isMatchingHead && isMatchingPayload;
|
|
@@ -235,7 +244,7 @@ export function getAttestationParticipationStatus(
|
|
|
235
244
|
if (isMatchingTarget && isTimelyTarget(fork, inclusionDelay)) flags |= TIMELY_TARGET;
|
|
236
245
|
if (isMatchingHead && inclusionDelay === MIN_ATTESTATION_INCLUSION_DELAY) flags |= TIMELY_HEAD;
|
|
237
246
|
|
|
238
|
-
return flags;
|
|
247
|
+
return {flags, isSameSlotAttestation};
|
|
239
248
|
}
|
|
240
249
|
|
|
241
250
|
export function checkpointValueEquals(cp1: phase0.Checkpoint, cp2: phase0.Checkpoint): boolean {
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import {FAR_FUTURE_EPOCH} from "@lodestar/params";
|
|
1
|
+
import {FAR_FUTURE_EPOCH, PAYLOAD_BUILDER_VERSION} from "@lodestar/params";
|
|
2
2
|
import {gloas} from "@lodestar/types";
|
|
3
3
|
import {CachedBeaconStateGloas} from "../types.js";
|
|
4
4
|
import {computeEpochAtSlot} from "../util/epoch.js";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
addBuilderToRegistry,
|
|
7
|
+
findBuilderIndexByPubkey,
|
|
8
|
+
isBuilderWithdrawalCredential,
|
|
9
|
+
isValidBuilderDepositSignature,
|
|
10
|
+
} from "../util/gloas.js";
|
|
6
11
|
|
|
7
12
|
/**
|
|
8
13
|
* Process a builder deposit request from the execution layer: register a new builder
|
|
@@ -15,6 +20,12 @@ export function processBuilderDepositRequest(
|
|
|
15
20
|
request: gloas.BuilderDepositRequest
|
|
16
21
|
): void {
|
|
17
22
|
const {pubkey, withdrawalCredentials, amount, signature} = request;
|
|
23
|
+
|
|
24
|
+
// Ignore deposits with unexpected withdrawal credential prefixes.
|
|
25
|
+
if (!isBuilderWithdrawalCredential(withdrawalCredentials)) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
18
29
|
const builderIndex = findBuilderIndexByPubkey(state, pubkey);
|
|
19
30
|
|
|
20
31
|
if (builderIndex === null) {
|
|
@@ -22,7 +33,7 @@ export function processBuilderDepositRequest(
|
|
|
22
33
|
addBuilderToRegistry(
|
|
23
34
|
state,
|
|
24
35
|
pubkey,
|
|
25
|
-
|
|
36
|
+
PAYLOAD_BUILDER_VERSION,
|
|
26
37
|
withdrawalCredentials.subarray(12),
|
|
27
38
|
amount,
|
|
28
39
|
state.slot
|
|
@@ -33,11 +44,13 @@ export function processBuilderDepositRequest(
|
|
|
33
44
|
|
|
34
45
|
const builder = state.builders.get(builderIndex);
|
|
35
46
|
|
|
36
|
-
//
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (builder.withdrawableEpoch !== FAR_FUTURE_EPOCH) {
|
|
47
|
+
// If the builder has exited and been fully swept (balance drained to 0), reset the
|
|
48
|
+
// withdrawable epoch so this top-up becomes withdrawable again. Must run before the
|
|
49
|
+
// balance increase, since the reset is gated on the current balance being 0.
|
|
50
|
+
if (builder.withdrawableEpoch !== FAR_FUTURE_EPOCH && builder.balance === 0) {
|
|
41
51
|
builder.withdrawableEpoch = computeEpochAtSlot(state.slot) + state.config.MIN_BUILDER_WITHDRAWABILITY_DELAY;
|
|
42
52
|
}
|
|
53
|
+
|
|
54
|
+
// Increase balance by deposit amount
|
|
55
|
+
builder.balance += amount;
|
|
43
56
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {PublicKey, Signature, verify} from "@chainsafe/blst";
|
|
2
2
|
import {BUILDER_INDEX_SELF_BUILD, GENESIS_SLOT, PAYLOAD_BUILDER_VERSION, SLOTS_PER_EPOCH} from "@lodestar/params";
|
|
3
|
-
import {gloas, ssz} from "@lodestar/types";
|
|
3
|
+
import {Slot, gloas, ssz} from "@lodestar/types";
|
|
4
4
|
import {byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
|
|
5
5
|
import {G2_POINT_AT_INFINITY} from "../constants/constants.js";
|
|
6
6
|
import {getExecutionPayloadBidSigningRoot} from "../signatureSets/executionPayloadBid.js";
|
|
@@ -11,7 +11,7 @@ import {getBlockRootAtSlot, getCurrentEpoch, getRandaoMix} from "../util/index.j
|
|
|
11
11
|
export function processExecutionPayloadBid(
|
|
12
12
|
state: CachedBeaconStateGloas,
|
|
13
13
|
signedBid: gloas.SignedExecutionPayloadBid
|
|
14
|
-
):
|
|
14
|
+
): Slot {
|
|
15
15
|
const bid = signedBid.message;
|
|
16
16
|
const {builderIndex, value: amount} = bid;
|
|
17
17
|
|
|
@@ -99,7 +99,10 @@ export function processExecutionPayloadBid(
|
|
|
99
99
|
state.builderPendingPayments.set(SLOTS_PER_EPOCH + (bid.slot % SLOTS_PER_EPOCH), pendingPaymentView);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
const parentSlot = state.latestExecutionPayloadBid.slot;
|
|
102
103
|
state.latestExecutionPayloadBid = ssz.gloas.ExecutionPayloadBid.toViewDU(bid);
|
|
104
|
+
|
|
105
|
+
return parentSlot;
|
|
103
106
|
}
|
|
104
107
|
|
|
105
108
|
function verifyExecutionPayloadBidSignature(
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
ForkSeq,
|
|
3
|
+
MAX_ATTESTATIONS_ELECTRA,
|
|
4
|
+
MAX_ATTESTER_SLASHINGS_ELECTRA,
|
|
5
|
+
MAX_BLS_TO_EXECUTION_CHANGES,
|
|
6
|
+
MAX_PAYLOAD_ATTESTATIONS,
|
|
7
|
+
MAX_PROPOSER_SLASHINGS,
|
|
8
|
+
MAX_VOLUNTARY_EXITS,
|
|
9
|
+
} from "@lodestar/params";
|
|
10
|
+
import {BeaconBlockBody, Slot, capella, electra, gloas} from "@lodestar/types";
|
|
3
11
|
import {BeaconStateTransitionMetrics} from "../metrics.js";
|
|
4
12
|
import {
|
|
5
13
|
CachedBeaconStateAllForks,
|
|
@@ -36,9 +44,14 @@ export function processOperations(
|
|
|
36
44
|
fork: ForkSeq,
|
|
37
45
|
state: CachedBeaconStateAllForks,
|
|
38
46
|
body: BeaconBlockBody,
|
|
47
|
+
parentSlot: Slot | null,
|
|
39
48
|
opts: ProcessBlockOpts = {verifySignatures: true},
|
|
40
49
|
metrics?: BeaconStateTransitionMetrics | null
|
|
41
50
|
): void {
|
|
51
|
+
if (fork >= ForkSeq.gloas) {
|
|
52
|
+
assertGloasOperationLimits(body as gloas.BeaconBlockBody);
|
|
53
|
+
}
|
|
54
|
+
|
|
42
55
|
// verify that outstanding deposits are processed up to the maximum number of deposits.
|
|
43
56
|
// From Fulu the eth1 bridge deposit mechanism was removed, so blocks must not contain any deposits.
|
|
44
57
|
const maxDeposits = fork >= ForkSeq.fulu ? 0 : getEth1DepositCount(state);
|
|
@@ -55,7 +68,7 @@ export function processOperations(
|
|
|
55
68
|
processAttesterSlashing(fork, state, attesterSlashing, opts.verifySignatures);
|
|
56
69
|
}
|
|
57
70
|
|
|
58
|
-
processAttestations(fork, state, body.attestations, opts.verifySignatures, metrics);
|
|
71
|
+
processAttestations(fork, state, body.attestations, parentSlot, opts.verifySignatures, metrics);
|
|
59
72
|
|
|
60
73
|
for (const deposit of body.deposits) {
|
|
61
74
|
processDeposit(fork, state, deposit);
|
|
@@ -94,3 +107,18 @@ export function processOperations(
|
|
|
94
107
|
}
|
|
95
108
|
}
|
|
96
109
|
}
|
|
110
|
+
|
|
111
|
+
function assertGloasOperationLimits(body: gloas.BeaconBlockBody): void {
|
|
112
|
+
assertMaxLength("proposerSlashings", body.proposerSlashings.length, MAX_PROPOSER_SLASHINGS);
|
|
113
|
+
assertMaxLength("attesterSlashings", body.attesterSlashings.length, MAX_ATTESTER_SLASHINGS_ELECTRA);
|
|
114
|
+
assertMaxLength("attestations", body.attestations.length, MAX_ATTESTATIONS_ELECTRA);
|
|
115
|
+
assertMaxLength("voluntaryExits", body.voluntaryExits.length, MAX_VOLUNTARY_EXITS);
|
|
116
|
+
assertMaxLength("blsToExecutionChanges", body.blsToExecutionChanges.length, MAX_BLS_TO_EXECUTION_CHANGES);
|
|
117
|
+
assertMaxLength("payloadAttestations", body.payloadAttestations.length, MAX_PAYLOAD_ATTESTATIONS);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function assertMaxLength(name: string, length: number, limit: number): void {
|
|
121
|
+
if (length > limit) {
|
|
122
|
+
throw new Error(`Block contains too many ${name}: count=${length} limit=${limit}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ForkPostGloas,
|
|
3
|
+
MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD,
|
|
4
|
+
MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD,
|
|
5
|
+
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD,
|
|
6
|
+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
|
|
7
|
+
SLOTS_PER_EPOCH,
|
|
8
|
+
SLOTS_PER_HISTORICAL_ROOT,
|
|
9
|
+
} from "@lodestar/params";
|
|
2
10
|
import {BeaconBlock, gloas, ssz} from "@lodestar/types";
|
|
3
11
|
import {byteArrayEquals, toRootHex} from "@lodestar/utils";
|
|
4
12
|
import {CachedBeaconStateGloas} from "../types.js";
|
|
@@ -47,6 +55,8 @@ export function processParentExecutionPayload(state: CachedBeaconStateGloas, blo
|
|
|
47
55
|
* Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.6/specs/gloas/beacon-chain.md#new-apply_parent_execution_payload
|
|
48
56
|
*/
|
|
49
57
|
export function applyParentExecutionPayload(state: CachedBeaconStateGloas, requests: gloas.ExecutionRequests): void {
|
|
58
|
+
assertExecutionRequestsWithinLimits(requests);
|
|
59
|
+
|
|
50
60
|
const fork = state.config.getForkSeq(state.slot);
|
|
51
61
|
const parentBid = state.latestExecutionPayloadBid;
|
|
52
62
|
const parentSlot = parentBid.slot;
|
|
@@ -116,6 +126,21 @@ function settleBuilderPayment(state: CachedBeaconStateGloas, paymentIndex: numbe
|
|
|
116
126
|
state.builderPendingPayments.set(paymentIndex, ssz.gloas.BuilderPendingPayment.defaultViewDU());
|
|
117
127
|
}
|
|
118
128
|
|
|
129
|
+
function assertExecutionRequestsWithinLimits(requests: gloas.ExecutionRequests): void {
|
|
130
|
+
assertMaxLength("withdrawals", requests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD);
|
|
131
|
+
assertMaxLength("consolidations", requests.consolidations.length, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD);
|
|
132
|
+
// New in GLOAS:EIP8282
|
|
133
|
+
assertMaxLength("builderDeposits", requests.builderDeposits.length, MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD);
|
|
134
|
+
// New in GLOAS:EIP8282
|
|
135
|
+
assertMaxLength("builderExits", requests.builderExits.length, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function assertMaxLength(name: string, length: number, limit: number): void {
|
|
139
|
+
if (length > limit) {
|
|
140
|
+
throw new Error(`Too many parent execution request ${name} count=${length} limit=${limit}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
119
144
|
function assertEmptyExecutionRequests(requests: gloas.ExecutionRequests): void {
|
|
120
145
|
if (
|
|
121
146
|
requests.deposits.length !== 0 ||
|
|
@@ -8,7 +8,11 @@ import {
|
|
|
8
8
|
import {electra, phase0, ssz} from "@lodestar/types";
|
|
9
9
|
import {toHex} from "@lodestar/utils";
|
|
10
10
|
import {CachedBeaconStateElectra, CachedBeaconStateGloas} from "../types.js";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
hasCompoundingWithdrawalCredential,
|
|
13
|
+
hasExecutionWithdrawalCredential,
|
|
14
|
+
isValidatorKnown,
|
|
15
|
+
} from "../util/electra.js";
|
|
12
16
|
import {computeExitEpochAndUpdateChurn} from "../util/epoch.js";
|
|
13
17
|
import {getPendingBalanceToWithdraw, isActiveValidator} from "../util/validator.js";
|
|
14
18
|
import {initiateValidatorExit} from "./initiateValidatorExit.js";
|
|
@@ -32,7 +36,7 @@ export function processWithdrawalRequest(
|
|
|
32
36
|
// bail out if validator is not in beacon state
|
|
33
37
|
// note that we don't need to check for 6110 unfinalized vals as they won't be eligible for withdraw/exit anyway
|
|
34
38
|
const validatorIndex = pubkeyCache.getIndex(withdrawalRequest.validatorPubkey);
|
|
35
|
-
if (validatorIndex
|
|
39
|
+
if (!isValidatorKnown(state, validatorIndex)) {
|
|
36
40
|
return;
|
|
37
41
|
}
|
|
38
42
|
|
|
@@ -99,7 +99,7 @@ export function processWithdrawals(
|
|
|
99
99
|
const stateGloas = state as CachedBeaconStateGloas;
|
|
100
100
|
|
|
101
101
|
// Store expected withdrawals for verification
|
|
102
|
-
stateGloas.payloadExpectedWithdrawals = ssz.
|
|
102
|
+
stateGloas.payloadExpectedWithdrawals = ssz.gloas.Withdrawals.toViewDU(expectedWithdrawals);
|
|
103
103
|
|
|
104
104
|
// Update builder pending withdrawals queue
|
|
105
105
|
stateGloas.builderPendingWithdrawals = stateGloas.builderPendingWithdrawals.sliceFrom(
|
package/src/cache/epochCache.ts
CHANGED
|
@@ -408,12 +408,17 @@ export class EpochCache {
|
|
|
408
408
|
|
|
409
409
|
const nextShuffling = cachedNextShuffling ?? computeEpochShuffling(state, nextActiveIndices, nextEpoch);
|
|
410
410
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
let proposers: number[];
|
|
411
|
+
let proposers: ValidatorIndex[];
|
|
412
|
+
let proposersNextEpoch: ProposersDeferred;
|
|
414
413
|
if (currentEpoch >= config.FULU_FORK_EPOCH) {
|
|
415
|
-
//
|
|
416
|
-
|
|
414
|
+
// After fulu, use state.proposerLookahead for current and next epoch proposers.
|
|
415
|
+
// Computing from the unfiltered active shuffling would include slashed validators in gloas.
|
|
416
|
+
const proposerLookahead = (state as CachedBeaconStateFulu).proposerLookahead.getAll();
|
|
417
|
+
proposers = proposerLookahead.slice(0, SLOTS_PER_EPOCH);
|
|
418
|
+
proposersNextEpoch = {
|
|
419
|
+
computed: true,
|
|
420
|
+
indexes: proposerLookahead.slice(SLOTS_PER_EPOCH, SLOTS_PER_EPOCH * 2),
|
|
421
|
+
};
|
|
417
422
|
} else {
|
|
418
423
|
// We need to calculate Pre-fulu
|
|
419
424
|
// Allow to create CachedBeaconState for empty states, or no active validators
|
|
@@ -421,18 +426,17 @@ export class EpochCache {
|
|
|
421
426
|
currentShuffling.activeIndices.length > 0
|
|
422
427
|
? computeProposers(
|
|
423
428
|
config.getForkSeqAtEpoch(currentEpoch),
|
|
424
|
-
|
|
429
|
+
getSeed(state, currentEpoch, DOMAIN_BEACON_PROPOSER),
|
|
425
430
|
currentShuffling,
|
|
426
431
|
effectiveBalanceIncrements
|
|
427
432
|
)
|
|
428
433
|
: [];
|
|
434
|
+
proposersNextEpoch = {
|
|
435
|
+
computed: false,
|
|
436
|
+
seed: getSeed(state, nextEpoch, DOMAIN_BEACON_PROPOSER),
|
|
437
|
+
};
|
|
429
438
|
}
|
|
430
439
|
|
|
431
|
-
const proposersNextEpoch: ProposersDeferred = {
|
|
432
|
-
computed: false,
|
|
433
|
-
seed: getSeed(state, nextEpoch, DOMAIN_BEACON_PROPOSER),
|
|
434
|
-
};
|
|
435
|
-
|
|
436
440
|
// Only after altair, compute the indices of the current sync committee
|
|
437
441
|
const afterAltairFork = currentEpoch >= config.ALTAIR_FORK_EPOCH;
|
|
438
442
|
|
|
@@ -713,17 +717,10 @@ export class EpochCache {
|
|
|
713
717
|
// Populate proposer cache with lookahead from state
|
|
714
718
|
const proposerLookahead = (state as CachedBeaconStateFulu).proposerLookahead.getAll();
|
|
715
719
|
this.proposers = proposerLookahead.slice(0, SLOTS_PER_EPOCH);
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
indexes: proposerLookahead.slice(SLOTS_PER_EPOCH, SLOTS_PER_EPOCH * 2),
|
|
721
|
-
};
|
|
722
|
-
} else {
|
|
723
|
-
// This should not happen unless MIN_SEED_LOOKAHEAD is set to 0
|
|
724
|
-
// this ensures things don't break if the proposer lookahead is not long enough
|
|
725
|
-
this.proposersNextEpoch = {computed: false, seed: getSeed(state, epochAfterUpcoming, DOMAIN_BEACON_PROPOSER)};
|
|
726
|
-
}
|
|
720
|
+
this.proposersNextEpoch = {
|
|
721
|
+
computed: true,
|
|
722
|
+
indexes: proposerLookahead.slice(SLOTS_PER_EPOCH, SLOTS_PER_EPOCH * 2),
|
|
723
|
+
};
|
|
727
724
|
} else {
|
|
728
725
|
// Need to calculate proposers pre-fulu
|
|
729
726
|
const upcomingProposerSeed = getSeed(state, upcomingEpoch, DOMAIN_BEACON_PROPOSER);
|
package/src/cache/stateCache.ts
CHANGED
|
@@ -254,11 +254,9 @@ export function isCachedBeaconState<T extends BeaconStateAllForks>(
|
|
|
254
254
|
// This cache is populated during epoch transition, and should be preserved for performance.
|
|
255
255
|
// If the cache is missing too often, means that our clone strategy is not working well.
|
|
256
256
|
export function isStateValidatorsNodesPopulated(state: CachedBeaconStateAllForks): boolean {
|
|
257
|
-
|
|
258
|
-
return state.validators["nodesPopulated"] === true;
|
|
257
|
+
return (state.validators as unknown as {nodesPopulated?: boolean}).nodesPopulated === true;
|
|
259
258
|
}
|
|
260
259
|
|
|
261
260
|
export function isStateBalancesNodesPopulated(state: CachedBeaconStateAllForks): boolean {
|
|
262
|
-
|
|
263
|
-
return state.balances["nodesPopulated"] === true;
|
|
261
|
+
return (state.balances as unknown as {nodesPopulated?: boolean}).nodesPopulated === true;
|
|
264
262
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import {zeroNode} from "@chainsafe/persistent-merkle-tree";
|
|
2
2
|
import {ssz} from "@lodestar/types";
|
|
3
|
-
import {
|
|
3
|
+
import type {BeaconStateAltair, BeaconStateGloas} from "../types.js";
|
|
4
|
+
import {isGloasStateType} from "../util/execution.js";
|
|
5
|
+
import {zeroProgressiveListBasicRootNode} from "../util/ssz.js";
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Updates `state.previousEpochParticipation` with precalculated epoch participation. Creates a new empty tree for
|
|
@@ -9,7 +11,12 @@ import {CachedBeaconStateAltair} from "../types.js";
|
|
|
9
11
|
* PERF: Cost = 'proportional' $VALIDATOR_COUNT. Since it updates all of them at once, it will always recreate both
|
|
10
12
|
* trees completely.
|
|
11
13
|
*/
|
|
12
|
-
export function processParticipationFlagUpdates(state:
|
|
14
|
+
export function processParticipationFlagUpdates(state: BeaconStateAltair | BeaconStateGloas): void {
|
|
15
|
+
if (isGloasStateType(state)) {
|
|
16
|
+
processParticipationFlagUpdatesGloas(state);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
13
20
|
// Set view and tree from currentEpochParticipation to previousEpochParticipation
|
|
14
21
|
state.previousEpochParticipation = state.currentEpochParticipation;
|
|
15
22
|
|
|
@@ -25,3 +32,14 @@ export function processParticipationFlagUpdates(state: CachedBeaconStateAltair):
|
|
|
25
32
|
|
|
26
33
|
state.currentEpochParticipation = ssz.altair.EpochParticipation.getViewDU(currentEpochParticipationNode);
|
|
27
34
|
}
|
|
35
|
+
|
|
36
|
+
function processParticipationFlagUpdatesGloas(state: BeaconStateGloas): void {
|
|
37
|
+
state.previousEpochParticipation = state.currentEpochParticipation;
|
|
38
|
+
|
|
39
|
+
// Same trick as the altair path above, adapted to the progressive-list tree shape: all chunks
|
|
40
|
+
// are zero so the chunks tree is a chain of pre-computed zeroNodes, built in O(log n) instead
|
|
41
|
+
// of re-merkleizing a validator-count-sized array every epoch.
|
|
42
|
+
state.currentEpochParticipation = ssz.gloas.EpochParticipation.getViewDU(
|
|
43
|
+
zeroProgressiveListBasicRootNode(ssz.gloas.EpochParticipation.itemsPerChunk, state.currentEpochParticipation.length)
|
|
44
|
+
);
|
|
45
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {ForkSeq, GENESIS_EPOCH} from "@lodestar/params";
|
|
2
|
-
import {ssz} from "@lodestar/types";
|
|
3
2
|
import {
|
|
4
3
|
CachedBeaconStateAllForks,
|
|
5
4
|
CachedBeaconStateAltair,
|
|
@@ -39,7 +38,7 @@ export function processRewardsAndPenalties(
|
|
|
39
38
|
|
|
40
39
|
// important: do not change state one balance at a time. Set them all at once, constructing the tree in one go
|
|
41
40
|
// cache the balances array, too
|
|
42
|
-
state.balances =
|
|
41
|
+
state.balances = state.type.fields.balances.toViewDU(balances);
|
|
43
42
|
|
|
44
43
|
// For processEffectiveBalanceUpdates() to prevent having to re-compute the balances array.
|
|
45
44
|
// For validator metrics
|